英文:
how to count the number of records with ExecuteScalar if more than one then cannot insert into in the MS Access database on vb.net
问题
以下是您提供的代码的中文翻译:
Private Sub Btnsave_Click(sender As Object, e As EventArgs) Handles Btnsave.Click
If txtWCSKILL.Text = "" Or txtWCEXPERIENCE.Text = "" Or txtWCAPPEARANCE.Text = "" Or txtWCEDUCATION.Text = "" Then
MessageBox.Show("WSKILL、WEXPERIENCE、WAPPEARANCE 和 WEDUCATION 不能为空。", "报告状态",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
txtWCSKILL.Focus()
Exit Sub
End If
Dim count As Integer
Using cmd As OleDbCommand = con.CreateCommand()
cmd.CommandText = "SELECT COUNT(*) FROM tblWeightingCriteria"
con.Open()
If count = CInt(cmd.ExecuteScalar() > 1) Then
MessageBox.Show("已存在一条记录!", "报告状态",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
con.Close()
Exit Sub
Else
Try
con.Open()
cmd.CommandText = "INSERT INTO tblWeightingCriteria" & "([WCSKILL],[WCEXPERIENCE],[WCAPPEARANCE],[WCEDUCATION]) " & "VALUES(@WCSKILL,@WCEXPERIENCE,@WCAPPEARANCE,@WCEDUCATION)"
cmd.Parameters.AddRange(New OleDbParameter() {
New OleDbParameter("@WCSKILL", DbNullOrStringValue(txtWCSKILL.Text)),
New OleDbParameter("@WCEXPERIENCE", DbNullOrStringValue(txtWCEXPERIENCE.Text)),
New OleDbParameter("@WCAPPEARANCE", DbNullOrStringValue(txtWCAPPEARANCE.Text)),
New OleDbParameter("@WCEDUCATION", DbNullOrStringValue(txtWCEDUCATION.Text))
})
Dim result = cmd.ExecuteNonQuery()
If result = 0 Then
MsgBox("未插入任何数据!")
Else
MsgBox("已成功插入新数据!")
End If
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Information)
End Try
End If
End Using
con.Close()
End Sub
希望这有所帮助。如果您需要进一步的解释或有其他问题,请随时提出。
英文:
I tried with the code below it doesn't work, is there something wrong with my code, please guide me.
or if there is another solution
Thanks
Private Sub Btnsave_Click(sender As Object, e As EventArgs) Handles Btnsave.Click
If txtWCSKILL.Text = "" Or txtWCEXPERIENCE.Text = "" Or txtWCAPPEARANCE.Text = "" Or txtWCEDUCATION.Text = "" Then
MessageBox.Show("WSKILL,WEXPERIENCE,WAPPEARANCE,WEDUCATION cannot be empty.", "Report Status",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
txtWCSKILL.Focus()
Exit Sub
End If
Dim count As Integer
Using cmd As OleDbCommand = con.CreateCommand()
cmd.CommandText = "Select COUNT(*) FROM tblWeightingCriteria"
con.Open()
If count = CInt(cmd.ExecuteScalar() > 1) Then
MessageBox.Show("One Record Already Exist!", "Report Status",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
con.Close()
Exit Sub
Else
Try
con.Open()
cmd.CommandText = "INSERT INTO tblWeightingCriteria" & "([WCSKILL],[WCEXPERIENCE],[WCAPPEARANCE],[WCEDUCATION]) " & "VALUES(@WCSKILL,@WCEXPERIENCE,@WCAPPEARANCE,@WCEDUCATION)"
cmd.Parameters.AddRange(New OleDbParameter() {
New OleDbParameter("@WCSKILL", DbNullOrStringValue(txtWCSKILL.Text)),
New OleDbParameter("@WCEXPERIENCE", DbNullOrStringValue(txtWCEXPERIENCE.Text)),
New OleDbParameter("@WCAPPEARANCE", DbNullOrStringValue(txtWCAPPEARANCE.Text)),
New OleDbParameter("@WCEDUCATION", DbNullOrStringValue(txtWCEDUCATION.Text))})
Dim result = cmd.ExecuteNonQuery()
If result = 0 Then
MsgBox("No Data has been Inserted!")
Else
MsgBox("New Data is Inserted succesfully!")
End If
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Information)
End Try
End If
End Using
con.Close()
End Sub
答案1
得分: 1
首先,你没有显示连接对象是在哪里创建的。
从MS Access过来,将连接持久化是一种长期编程方法,但在使用.net时不需要这样做。换句话说,不要尝试持久化连接对象。因此,在MS Access + VBA中编写代码时,您可以并且通常应该强制保持与数据库的连接处于打开状态。
在vb.net中,您不必这样做,实际上也不应该这样做。
接下来,启动Access并创建一个查询,然后键入以下内容:
请注意,即使数据库中没有任何行,您仍然会得到一行返回!
当我运行上面的查询时,我得到以下结果:
因此,返回的数据是一行数据,计数为0。
因此,从这样的查询中,您将始终获得1条记录,即使表中不存在任何行也是如此。
您的逻辑是,一旦向该表插入一条记录,您将在应用程序的整个生命周期内永远不再向该表插入行。这意味着插入代码可以且将仅运行一次。
我怀疑您是想测试/检查当前记录是否存在,因为您目前的逻辑没有太多意义。
我是说,一旦您向该表插入记录,您就不会再使用那一行,而且您永远不会再次插入该表吗?
因此,在理论上,您有一个只能包含一行数据的表,但在插入记录后,您将永远不会再次插入数据到该表?
您确定这是您想要的设计吗?因此,该表只能永远插入一行数据,并且从那时起的100年内,您永远不会再添加另一行吗?
我猜最大的问题是您是否要更新或更改该表中仅有的一行数据?
您的上面的代码是否打算再次更新那一行?
现在,我无法确定您的逻辑是:
*我们只在100年内插入一行,然后在接下来的100年内再也不会触碰那一行数据?
*还是我们要检查是否没有行存在,如果没有行存在,那么我们插入一行,但是如果已经存在一行,那么我想使用新值更新那一行?
如果没有行存在,则插入新行并使用您的值。
如果存在1行,则使用新值更新该行。
对我来说,上述的方法更有道理。
然而,让我们将其编写为只在接下来的100年内插入一行,因此永远不再插入。
因此,这段代码看起来是可行的:
If txtWCSKILL.Text = "" Or
txtWCEXPERIENCE.Text = "" Or
txtWCAPPEARANCE.Text = "" Or
txtWCEDUCATION.Text = "" Then
MessageBox.Show("WSKILL, WEXPERIENCE, WAPPEARANCE, WEDUCATION 不能为空。", "报告状态",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
txtWCSKILL.Focus()
Exit Sub
End If
Using cmd As New OleDbCommand("SELECT * FROM tblWeightingCriteria")
Using conn As New OleDbConnection(My.Settings.TEST4)
conn.Open()
Dim rstData As New DataTable
rstData.Load(cmd.ExecuteReader)
If rstData.Rows.Count > 0 Then
MessageBox.Show("已经存在一条记录!", "报告状态",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
Exit Sub
End If
'不存在,因此创建行
Dim MyRow As DataRow = rstData.NewRow
MyRow("WCSKILL") = txtWCSKILL.Text
MyRow("WCEXPERIENCE") = txtWCSKILL.Text
MyRow("WCAPPEARANCE") = txtWCAPPEARANCE.Text
MyRow("WCEDUCATION") = txtWCEDUCATION.Text
rstData.Rows.Add(MyRow)
Dim da As New OleDbDataAdapter(cmd)
Dim daU As New OleDbCommandBuilder(da)
da.Update(rstData)
End Using
End Using
请注意,我们始终假定连接已经关闭。如果您收到关于连接已经打开的错误,那么我们可以假定您的代码中存在错误。
现在,非常有可能您需要/想要使用新值更新1行,但如果不存在行,则创建行。因此,我们可以使用上面的相同代码进行插入或更新。
因此,代码变为:
(逻辑:如果没有行,创建+然后编辑)
(如果存在行,则编辑)
If txtWCSKILL.Text = "" Or
txtWCEXPERIENCE.Text = "" Or
txtWCAPPEARANCE.Text = "" Or
txtWCEDUCATION.Text = "" Then
MessageBox.Show("WSKILL, WEXPERIENCE, WAPPEARANCE, WEDUCATION 不能为空。", "报告状态",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
txtWCSKILL.Focus()
Exit Sub
End If
Using cmd As New OleDbCommand("SELECT * FROM tblWeightingCriteria")
Using conn As New OleDbConnection(My.Settings.TEST4)
conn.Open()
Dim rstData As New DataTable
rstData.Load(cmd.ExecuteReader)
Dim MyRow As DataRow
If rstData.Rows.Count > 0 Then
'行不存在,因此创建它
MyRow = rstData.NewRow
Else
'行已存在,因此我们将修改此现有行
MyRow = rstData.Rows(0)
End If
MyRow("WCSKILL") = txtWCSKILL.Text
MyRow("WCEXPERIENCE") = txtWCSKILL.Text
MyRow("WCAPPEARANCE") = txtWCAPPEARANCE.Text
MyRow("WCEDUCATION") = txtWCEDUCATION.Text
If rstData.Rows.Count = 0 Then
rstData.Rows.Add(MyRow)
End If
Dim da As New OleDbDataAdapter(cmd)
Dim daU As New OleDbCommandBuilder(da
<details>
<summary>英文:</summary>
First of all, you don't show where your connection object was created.
Coming from MS Access, it is long time coding approach to persist the connection, but you do not do this when using .net. In other words, don't try and persist a connection object. So, when writing code in MS Access + VBA, you can and often should force a connection to remain open to the database.
In vb.net, you don't have to do this, and in fact you don't want to.
Next up, fire up access and create a query, and type in this:
[![enter image description here][1]][1]
Note that EVEN when there are zero rows in the database, you STILL get a row back!
When I run the above query, I get this result:
[![enter image description here][2]][2]
So, the data returned is ONE row of data, and a count = 0.
So, you will ALWAYS get 1 record from such a query, EVEN when zero rows exist in the table.
Your logic is that once a record is inserted to that table, you will NEVER for the next 100 years ever again insert a row into that table. That means the insert code can and will only run one time for the WHOLE LIFE of the application.
I suspect that you looking to test/check if the current record exists, since the logic you have so far does not make a whole lot of sense.
I mean, once you inserted a record into that table, you are to never use that that one row, and you NEVER insert again into that table?
So, in theory, you have a table that will only ever have one row of data, but after you insert a record, you will never insert data again to that table?
Are you sure that's the design you want here? So that table only is ever to have one inserted row of data, and from that point for next 100 years, you never add another row?
I guess the big question then do you ever want to update or change that one row in that table that will only ever have one row?
And does your above code ever supposed to update that one row again?
Now, I can't tell if you logic is:
* We only ever for 100 years insert one row, and NEVER touch that one row of data again for the next 100 years?
* Or we want to check if no rows exist, and if no rows, we insert the one row, however, if one row exists, then I want to update that one existing row with the new values?
If no rows, insert new row with your values.
If 1 existing row, then update that row with your new values.
Seems to me, the above makes more sense.
However, let's write this to only EVER for the next 100 years insert the one row , and thus NEVER again ever insert.
So, this code looks to be workable:
If txtWCSKILL.Text = "" Or
txtWCEXPERIENCE.Text = "" Or
txtWCAPPEARANCE.Text = "" Or
txtWCEDUCATION.Text = "" Then
MessageBox.Show("WSKILL,WEXPERIENCE,WAPPEARANCE,WEDUCATION cannot be empty.", "Report Status",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
txtWCSKILL.Focus()
Exit Sub
End If
Using cmd As New OleDbCommand("SELECT * FROM tblWeightingCriteria")
Using conn As New OleDbConnection(My.Settings.TEST4)
conn.Open()
Dim rstData As New DataTable
rstData.Load(cmd.ExecuteReader)
If rstData.Rows.Count > 0 Then
MessageBox.Show("One Record Already Exist!", "Report Status",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
Exit Sub
End If
' does not exist, so create the row
Dim MyRow As DataRow = rstData.NewRow
MyRow("WCSKILL") = txtWCSKILL.Text
MyRow("WCEXPERIENCE") = txtWCSKILL.Text
MyRow("WCAPPEARANCE") = txtWCAPPEARANCE.Text
MyRow("WCEDUCATION") = txtWCEDUCATION.Text
rstData.Rows.Add(MyRow)
Dim da As New OleDbDataAdapter(cmd)
Dim daU As New OleDbCommandBuilder(da)
da.Update(rstData)
End Using
End Using
Note that we ALWAYS assume the connection was and will be and has been closed. If you get a error about the connection open already, then we can assume you have a bug in your code.
Now, it is VERY possible that you need/want to update the 1 row with the new values, but create the row if ZERO rows exist. Thus, we can use the above same code for a insert, or a update.
So, the code then becomes this:
(logic: if no rows, create + then edit)
(if existing row, then edit)_
If txtWCSKILL.Text = "" Or
txtWCEXPERIENCE.Text = "" Or
txtWCAPPEARANCE.Text = "" Or
txtWCEDUCATION.Text = "" Then
MessageBox.Show("WSKILL,WEXPERIENCE,WAPPEARANCE,WEDUCATION cannot be empty.", "Report Status",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
txtWCSKILL.Focus()
Exit Sub
End If
Using cmd As New OleDbCommand("SELECT * FROM tblWeightingCriteria")
Using conn As New OleDbConnection(My.Settings.TEST4)
conn.Open()
Dim rstData As New DataTable
rstData.Load(cmd.ExecuteReader)
Dim MyRow As DataRow
If rstData.Rows.Count > 0 Then
' row does not exist, so create it
MyRow = rstData.NewRow
Else
' row eixsts, so we will modify this existing row
MyRow = rstData.Rows(0)
End If
MyRow("WCSKILL") = txtWCSKILL.Text
MyRow("WCEXPERIENCE") = txtWCSKILL.Text
MyRow("WCAPPEARANCE") = txtWCAPPEARANCE.Text
MyRow("WCEDUCATION") = txtWCEDUCATION.Text
If rstData.Rows.Count = 0 Then
rstData.Rows.Add(MyRow)
End If
Dim da As New OleDbDataAdapter(cmd)
Dim daU As New OleDbCommandBuilder(da)
da.Update(rstData)
End Using
End Using
And note in above code, we CREATE the connection object each time. You have to change my.Settings.TEST4 to your connecting that you build and placed in the application settings (since you not going to type in connecting string in the code, as that too difficult to maintain).
[1]: https://i.stack.imgur.com/A984d.png
[2]: https://i.stack.imgur.com/evWFc.png
</details>
# 答案2
**得分**: 1
以下是翻译好的部分:
- `count` 是 `Integer` 类型,而 `CInt(cmd.ExecuteScalar() > 1)` 返回一个 `Boolean` 值,所以显然您的 `Option Strict` 设置为 `Off`,允许隐式转换。如果将选项设置为 `On`,则会出现 [BC30512][1] 错误:
> _Option Strict On 不允许从 'Boolean' 到 'Integer' 的隐式转换。_
为了避免出现意外结果和类似的错误,请确保通过以下代码或项目属性将这些选项打开/关闭:
```vb.net
Option Explicit On
Option Strict On
Option Infer On
```
或通过项目的属性:
`Project` -> `YourProjectName Properties` -> `Compile`。
并将 `Explicit`、`Strict` 和 `Infer` 打开。我相信您的调试器将开始报告一些错误需要修复。至少,在您的下一个项目中考虑这样做。
- `COUNT(*)` 或 `COUNT(TheIdField)` 查询返回给定表的 `n` 行/记录。如果表为空,那么您肯定会得到 `0`。因此,如果要允许插入一条记录,请使用以下代码:
```vb.net
Using con = New OleDbConnection("..."), cmd = con.CreateCommand()
cmd.CommandText = "select count(*) from tblWeightingCriteria"
con.Open()
Dim count = Convert.ToInt32(cmd.ExecuteScalar())
If count > 0 Then
' 弹出警告并退出子程序。
Exit Sub
End If
' 否则,继续...
End Using
```
请注意,不要将数据访问对象(`OleDbConnection`、`OleDbCommand`、`OleDbDataAdapter` 等)保留在类字段中。在 [`Using`][3] 块中的 [CRUD][2] 方法中创建它们。这样,您不需要显式关闭连接或处理可释放的对象。`Using` 语句会为您执行这些操作。
- 分离您的代码并创建专门的方法。
创建连接的方法如下:
```vb.net
Private Function CreateConnection() As OleDbConnection
Return New OleDbConnection("Your connection string;")
End Function
```
用于 `CRUD` 操作和辅助方法的示例代码如下:
```vb.net
Private Function InsertData() As Integer
Using con = CreateConnection(), cmd = con.CreateCommand()
cmd.CommandText = "INSERT INTO tblWeightingCriteria " &
"([WCSKILL], [WCEXPERIENCE], [WCAPPEARANCE], [WCEDUCATION]) " &
"VALUES (?, ?, ?, ?)"
cmd.Parameters.AddRange({
New OleDbParameter("?", OleDbType.VarChar) With {
.Value = DbNullOrStringValue(txtWCSKILL.Text)},
New OleDbParameter("?", OleDbType.VarChar) With {
.Value = DbNullOrStringValue(txtWCEXPERIENCE.Text)},
New OleDbParameter("?", OleDbType.VarChar) With {
.Value = DbNullOrStringValue(txtWCAPPEARANCE.Text)},
New OleDbParameter("?", OleDbType.VarChar) With {
.Value = DbNullOrStringValue(txtWCEDUCATION.Text)}
})
con.Open()
Return cmd.ExecuteNonQuery()
End Using
End Function
' ...其他方法
```
请注意,OLE DB 提供程序[不支持命名参数][4]。请使用 `?` 作为占位符,并按照数据库字段的相同顺序添加参数,如上所示。
现在您的 `save` 调用者应该如下所示:
```vb.net
Private Sub btnInsert_Click(sender As Object, e As EventArgs) _
Handles btnInsert.Click
Dim inputBoxes = {
txtWCSKILL,
txtWCEXPERIENCE,
txtWCAPPEARANCE,
txtWCEDUCATION
}
If inputBoxes.Any(Function(tb) tb.Text.Trim().Length = 0) Then
MessageBox.Show("... 不能为空。",
"报告状态",
MessageBoxButtons.OK,
MessageBoxIcon.Warning)
inputBoxes(0).Select()
Return ' 或 Exit Sub
End If
Try
If GetCount() > 0 Then
MessageBox.Show("已经存在一条记录!",
"报告状态",
MessageBoxButtons.OK,
MessageBoxIcon.Warning)
Return
End If
Dim result = InsertData()
If result = 0 Then
MessageBox.Show("未插入任何数据!")
Else
MessageBox.Show("已成功插入新数据!")
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
```
- 此外,请考虑实施 n-tier 或类似用途的架构。将 UI 或呈现层放在一个项目/层中。数据访问在另一个层/项目(DAL)中。并且中间业务逻辑层(BLL)用于它们之间的通信。
更多阅读和示例:
- [在 n-tier 应用程序中使用数据集][5]
- [在 C# 中编写 N-Tier 应用程序][6]
<details>
<summary>英文:</summary>
Several points to consider.
You have this line:
```vb.net
If count = CInt(cmd.ExecuteScalar() > 1) Then
count
is of type Integer
and CInt(cmd.ExecuteScalar() > 1)
returns a Boolean
value, so obviously you have the Option Strict
set to Off
and the implicit conversions are allowed. If you turn the option On
, you'll get the BC30512 error:
> Option Strict On disallows implicit conversions from 'Boolean' to 'Integer'.
To avoid getting unexpected results and errors like this, make sure to turn this and other on/off options on by code:
Option Explicit On
Option Strict On
Option Infer On
Or through the project's properties:
Project
-> YourProjectName Properties
-> Compile
.
and turn the Explicit
, Strict
, and Infer
On. I'm sure your debugger will start complaining and report some errors to fix. At least, consider doing this in your next project.
The COUNT(*)
or COUNT(TheIdField)
query returns the n
rows/records of the given table. If the table is empty, then you'll get 0
for sure. So, if you want to allow inserting just one record:
Using con = New OleDbConnection("..."), cmd = con.CreateCommand()
cmd.CommandText = "select count(*) from tblWeightingCriteria"
con.Open()
Dim count = Convert.ToInt32(cmd.ExecuteScalar())
If count > 0 Then
' Alert and exit the sub.
Exit Sub
End If
' Otherwise, proceed...
End Using
Note, don't keep the data access objects (OleDbConnection
, OleDbCommand
, OleDbDataAdapter
, ...etc) in class fields. Create them in the CRUD methods in Using
block. This way, you don't need to explicitly close a connection or dispose of a disposable object. The Using
statement will do that for you.
Separate your code and create specialized methods.
To create a connection:
Private Function CreateConnection() As OleDbConnection
Return New OleDbConnection("Your connection string;")
End Function
For the CRUD
operations and helpers methods:
Private Function InsertData() As Integer
Using con = CreateConnection(), cmd = con.CreateCommand()
cmd.CommandText = "INSERT INTO tblWeightingCriteria " &
"([WCSKILL], [WCEXPERIENCE], [WCAPPEARANCE], [WCEDUCATION]) " &
"VALUES (?, ?, ?, ?)"
cmd.Parameters.AddRange({
New OleDbParameter("?", OleDbType.VarChar) With {
.Value = DbNullOrStringValue(txtWCSKILL.Text)},
New OleDbParameter("?", OleDbType.VarChar) With {
.Value = DbNullOrStringValue(txtWCEXPERIENCE.Text)},
New OleDbParameter("?", OleDbType.VarChar) With {
.Value = DbNullOrStringValue(txtWCAPPEARANCE.Text)},
New OleDbParameter("?", OleDbType.VarChar) With {
.Value = DbNullOrStringValue(txtWCEDUCATION.Text)}
})
con.Open()
Return cmd.ExecuteNonQuery()
End Using
End Function
Private Function DbNullOrStringValue(value As String) As Object
If String.IsNullOrEmpty(value) Then
Return DBNull.Value
Else
Return value
End If
End Function
Private Function LoadData() As DataTable
Dim dt As New DataTable()
Using con = CreateConnection(), cmd = con.CreateCommand(),
ta = New OleDbDataAdapter(cmd)
cmd.CommandText = "Select * From tblWeightingCriteria"
ta.Fill(dt)
End Using
Return dt
End Function
Private Function GetCount() As Integer
Using con = CreateConnection(), cmd = con.CreateCommand()
cmd.CommandText = "select count(*) from tblWeightingCriteria"
con.Open()
Return Convert.ToInt32(cmd.ExecuteScalar())
End Using
End Function
' ...etc.
Note, the OLE DB provider does not support named parameters. Use ?
as placeholders and add the parameters in the same order of the database fields as shown above.
Now your save
caller should look like this:
Private Sub btnInsert_Click(sender As Object, e As EventArgs) _
Handles btnInsert.Click
Dim inputBoxes = {
txtWCSKILL,
txtWCEXPERIENCE,
txtWCAPPEARANCE,
txtWCEDUCATION
}
If inputBoxes.Any(Function(tb) tb.Text.Trim().Length = 0) Then
MessageBox.Show("... cannot be empty.",
"Report Status",
MessageBoxButtons.OK,
MessageBoxIcon.Warning)
inputBoxes(0).Select()
Return ' or Exit Sub
End If
Try
If GetCount() > 0 Then
MessageBox.Show("One Record Already Exists!",
"Report Status",
MessageBoxButtons.OK,
MessageBoxIcon.Warning)
Return
End If
Dim result = InsertData()
If result = 0 Then
MessageBox.Show("No Data has been Inserted!")
Else
MessageBox.Show("New Data is Inserted succesfully!")
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Also, consider implementing the n-tier or a similar purpose architecture. Have the UI or the presentation in a layer/tier in one project. The data access in another layer/tier (DAL) and project. And a middle business logic layer (BLL) to communicate between them.
Further reading and examples.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论