locked
N-tier passing dataset from DAL to BLL and BLL to DAL RRS feed

  • Question

  • HI

    i'm using an N-tier solution. WinForm and sql server DB

    The DB ha just table with ine row 

    The following is the DAL code

    Just a Sub to create a Dataset  from DB and one Sub to update  DB

    Note that the  DAL DAL Dataset is  a Public Shared Property

    Imports System.Data.SqlClient
    Imports Libreria
    Imports System.Windows.Forms
    
    Public Class DALAttivita
    	' DAL - DATA ACCESS LAYER
    
    
    	Private Property QueryS As String
    	Private Property Lastex As Exception
    	Private Property DALAdapter As New SqlDataAdapter
    	Public Shared Property DALDataset As New DataSet
    
    
    	Public Sub SubGetAttivita()
    		' testa la connessione prima di iniziare
    		QueryS = <sql>
    					SELECT 
    						 [AttivitaID]
    						,[RagioneSociale]
    						,[Indirizzo]
    					FROM Tabelle.[Attivita]
    					</sql>.Value
    
    		Using CONN As New SqlConnection With {.ConnectionString = VG.FullCS}
    			Using CMD As New SqlCommand With {.Connection = CONN,
    				.CommandType = CommandType.Text, .CommandText = QueryS}
    
    				' crea il comando SELECT
    				DALAdapter.SelectCommand = CMD
    				Dim Builder As New SqlCommandBuilder(DALAdapter)
    
    				DALAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
    				DALAdapter.TableMappings.Add("Table", "Attivita")
    				Try
    					CONN.Open()
    					DALAdapter.Fill(DALDataset, "Attivita")
    					DALAdapter.Dispose()
    					CONN.Close()
    				Catch ex As Exception
    					MessageBox.Show("Errore lettura Achivio")
    					Lastex = ex
    					MessageBox.Show(ex.ToString)
    				End Try
    			End Using
    		End Using
    
    	End Sub
    
    	Public Sub SubSaveAttivita()
    		Using CONN As New SqlConnection With {.ConnectionString = VG.FullCS}
    			Using CMD As New SqlCommand With {.Connection = CONN, .CommandType =
    				CommandType.Text, .CommandText = QueryS}
    				DALAdapter.SelectCommand = CMD
    				Try
    					CONN.Open()
    
    					DALAdapter.Update(DALDataset.Tables("Attivita"))
    
    					DALAdapter.Dispose()
    					CONN.Close()
    				Catch ex As Exception
    					Lastex = ex
    					MessageBox.Show("Errore salvataggio Achivio")
    					MessageBox.Show(ex.ToString)
    				End Try
    			End Using
    		End Using
    	End Sub
    End Class

    Now the following is the BLL code

    ' BLL
    Imports DataAccessLayer
    Public Class BLLAttivita
    
    	Private Property DAL As New DALAttivita
    	Private Property BLLAtt As ClasseAttivita
    
    	Private Property BLLDataset As New DataSet
    	Private Property BLLRow As DataRow
    
    	Public Function FunGetAttivita() As ClasseAttivita
    
    
    		'	BLLDataset = DAL.FunGetAttivita() 'prende il dataset come return
    		DAL.SubGetAttivita()
    		BLLDataset = DALAttivita.DALDataset
    		For Each R As DataRow In BLLDataset.Tables("Attivita").Rows
    			' oppure cosi ?
    			' For Each R As DataRow In DALAttivita.DALDataset.Tables("Attivita").Rows
    			BLLAtt = New ClasseAttivita With {
    				.AttivitaID = R(0).ToString,
    				.RagioneSociale = R(1),
    				.Indirizzo = R(2)
    				}
    
    		Next
    		Return BLLAtt
    	End Function
    
    
    	Public Sub SUBSaveAttivita(ByVal BLLAtt As ClasseAttivita)
    
    		Dim BLLTable = BLLDataset.Tables("Attivita")
    		BLLRow = BLLTable.Rows.Find(1)
    		' oppure cosi ?
    		' BLLRow = DALAttivita.DALDataset.Tables("Attivita").Rows.Find(1)
    		BLLRow.BeginEdit()
    		BLLRow("RagioneSociale") = BLLAtt.RagioneSociale
    		BLLRow("Indirizzo") = BLLAtt.Indirizzo
    		BLLRow.EndEdit()
    		DAL.SubSaveAttivita()
    
    	End Sub
    
    End Class

    Note that in BLL afte calling DAL.SubGetAttivita() I copy DALDataset to  BLLDataset

    Then I apply the changes from UI to BLLDataset and call DAL.SubSaveAttivita()    WITHOUT passing back to DAL the BLLDataset

    EVERYTHING WORKS WHEN THE DB is updated

    The question is,  why the DAL can get the changes made in BLLDataset if it does not get back the BLLDataset ?

    Saturday, January 6, 2018 12:08 PM

Answers

  • If, I'm following all of this correctly, then yes you should be able to simply refer to DALDataSet in DALAttivita. 

    I believe this statement is correct:

    "By my thinking if BLLDataset is a reference to DALDataset, all changes made in BLLDATAset IN BLL class are changes to DALDataset in DAL - The fisical Dataset in memory is only ONE. "

    As long as you are accessing a reference to a single instance of the DataSet, then all changes are reflected within that instance regardless of where you pass it off to.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Claudio111 Saturday, January 6, 2018 4:27 PM
    Saturday, January 6, 2018 3:59 PM

All replies

  • Are you calling DALAttivita.SubGetAttivita() after using the methods in BLLAttivita?

    You are using different instances of DataSet in each class so the only way for the DAL to see any changes made in the BLL is for it to requery the data after the changes are made.

    You might want to consider refactoring the code... get rid of the shared dataset member and explicitly pass a reference to a single dataset (which could still be a public member of the DAL).  I suspect that the shared member is confusing you.

    It might also be worth reviewing N-Tier development... you have the BLL creating an instance of the DAL and that's probably not a good idea.  You should likely only have one instance of the DAL which other classes reference.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, January 6, 2018 1:28 PM
  • May be i was not clear. The program work well. I thonl it should not work since I dont pass back dataset from BLL to DAL after i changed the table in BLL
    Saturday, January 6, 2018 1:48 PM
  • May be i was not clear. The program work well. I thonl it should not work since I dont pass back dataset from BLL to DAL after i changed the table in BLL

    Sorry, I missed the line where you assign BLLDataset = DALAttivita.DALDataset after creating a new DataSet for BLLDataSet (no need for the new keyword in the declaration).

    So it works because you're using the shared instance of the dataset.

    As I suspected, it looks like that shared property is causing confusion for you.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, January 6, 2018 2:05 PM
  • Hi reed

    ok I forget Shared Property

    Now the DALDataset is just Public. and it is passed to BLL in the FunGetAttivita

    Maybe I have not understood one thing

    If I call  FunGetAttivita with this istruction

    BLLDataset = DAL.FunGetAttivita()

    do I  get a copy of Dataset ( with other memry occupied) or BLLDataset has a just refences to DALDataset ?

    Saturday, January 6, 2018 2:13 PM
  • In the code you posted, that method returns an instance of ClasseAttivita not a dataset so that line of code would be invalid unless you've changed the method definition.

    That said, the DataSet is a reference type so if you are returning the DataSet instance it is a reference to the instance not a copy of all of the data.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, January 6, 2018 2:20 PM
  • so the following should be the right code
    ' BLL
    'DAL
    Imports DatabaseOperation
    Imports System.Data.SqlClient
    Imports Libreria
    Imports System.Windows.Forms
    
    Public Class DALAttivita
    
    	Private Property QueryS As String
    	Private Property Lastex As Exception
    	Private Property DALTable As DataTable
    	Private Property DALDataset As New DataSet
    	Private Property DALAdapter As New SqlDataAdapter
    
    	Public Function FunGetAttivita() As DataSet
    		' testa prima la connessione
    		' ops.DBtestConnection()
    		QueryS = <sql>
    					SELECT 
    						 [AttivitaID]
    						,[RagioneSociale]
    						,[Indirizzo]
    					FROM Tabelle.[Attivita]
    					</sql>.Value
    
    		Using CONN As New SqlConnection With {.ConnectionString = VG.FullCS}
    			Using CMD As New SqlCommand With {.Connection = CONN,
    				.CommandType = CommandType.Text, .CommandText = QueryS}
    
    				' crea il comando SELECT
    				DALAdapter.SelectCommand = CMD
    				Dim Builder As New SqlCommandBuilder(DALAdapter)
    
    				DALAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
    				DALAdapter.TableMappings.Add("Table", "Attivita")
    				Try
    					CONN.Open()
    					DALAdapter.Fill(DALDataset, "Attivita")
    					DALAdapter.Dispose()
    					CONN.Close()
    				Catch ex As Exception
    					MessageBox.Show("Errore lettura Achivio")
    					Lastex = ex
    					MessageBox.Show(ex.ToString)
    				End Try
    			End Using
    		End Using
    		Return DALDataset
    	End Function
    
    	Public Function FunSaveAttivita(ByVal MioDatset As DataSet) As Boolean
    		Using CONN As New SqlConnection With {.ConnectionString = VG.FullCS}
    			Using CMD As New SqlCommand With {.Connection = CONN, .CommandType =
    				CommandType.Text, .CommandText = QueryS}
    				DALAdapter.SelectCommand = CMD
    				Try
    					CONN.Open()
    					DALAdapter.Update(DALDataset.Tables("Attivita"))
    
    					CONN.Close()
    				Catch ex As Exception
    					Lastex = ex
    					MessageBox.Show("Errore salvataggio Achivio")
    					MessageBox.Show(ex.ToString)
    				End Try
    			End Using
    		End Using
    		Return True  ' to be changed with exception...to do
    	End Function
    
    End Class
    

    Imports DataAccessLayer
    
    Public Class BLLAttivita
    
    	Private Property DAL As New DALAttivita
    	Private Property BLLAtt As ClasseAttivita
    	Private Property BLLDataset As DataSet
    	Private Property BLLRow As DataRow
    
    	Public Function FunGetAttivita() As ClasseAttivita
    
    		BLLDataset = DAL.FunGetAttivita() 'prende il dataset
    		For Each R As DataRow In BLLDataset.Tables("Attivita").Rows
    			BLLAtt = New ClasseAttivita With {
    				.AttivitaID = R(0).ToString,
    				.RagioneSociale = R(1),
    				.Indirizzo = R(2)
    				}
    
    		Next
    		Return BLLAtt
    	End Function
    
    
    	Public Function FunSaveAttivita(ByVal BLLAtt As ClasseAttivita) As Boolean
    
    		Dim BLLTable = BLLDataset.Tables("Attivita")
    
    		BLLRow = BLLTable.Rows.Find(1)
    		BLLRow.BeginEdit()
    		' la chiave primaria non puo' essere modifica
    		' BLLRow(0) = BLLAtt.AttivitaID
    		BLLRow("RagioneSociale") = BLLAtt.RagioneSociale
    		BLLRow("Indirizzo") = BLLAtt.Indirizzo
    		BLLRow.EndEdit()
    
    		DAL.FunSaveAttivita(BLLDataset)
    		Return True
    	End Function
    
    
    End Class
    
    If it is the right code why DALDataset should be Public - It seems it can be Private
    Saturday, January 6, 2018 2:39 PM
  • Now that you are passing the reference via a method call, you are correct that the underlying variable can be private.  It only needed to be public if you were going to access it from the DLL instance as a property member.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Claudio111 Saturday, January 6, 2018 3:05 PM
    • Unmarked as answer by Claudio111 Saturday, January 6, 2018 3:08 PM
    Saturday, January 6, 2018 2:45 PM
  • Last Question (I hope)

    In the last code posted it is true that I can call

    DAL.FunSaveAttivita(BLLDataset)

    even in this way

    DAL.DAL.FunSaveAttivita() ...i mean without pass BLLDataset ?

    (Of course modifing also the method in DAL) 

    By my thinking if BLLDataset is a reference to DALDataset, all changes made in BLLDATAset IN BLL class are changes to DALDataset in DAL - The fisical Dataset in memory is only ONE. 

    It is Right  ?

    Saturday, January 6, 2018 3:16 PM
  • If, I'm following all of this correctly, then yes you should be able to simply refer to DALDataSet in DALAttivita. 

    I believe this statement is correct:

    "By my thinking if BLLDataset is a reference to DALDataset, all changes made in BLLDATAset IN BLL class are changes to DALDataset in DAL - The fisical Dataset in memory is only ONE. "

    As long as you are accessing a reference to a single instance of the DataSet, then all changes are reflected within that instance regardless of where you pass it off to.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Claudio111 Saturday, January 6, 2018 4:27 PM
    Saturday, January 6, 2018 3:59 PM
  • Pk. Thank you very much. Everything is clear now.
    Saturday, January 6, 2018 4:27 PM
  • Pk. Thank you very much. Everything is clear now.

    Well understand the difference between Layered and n-tier.

    https://msdn.microsoft.com/en-us/library/ee658117.aspx

    Find out about other patterns....

    https://msdn.microsoft.com/en-us/library/ff649690.aspx

    https://www.codeproject.com/Reference/731015/The-repository-pattern-in-VB-Net

    http://blog.sapiensworks.com/post/2012/11/01/Repository-vs-DAO.aspx

    DAO pattern can be used with .NET languages such a C# and VB.NET 

    https://en.wikipedia.org/wiki/Data_access_object

    You may want to get it and learn more of what is happening in architecting .NET solutions.

    You get all the source code, you can run it all in debug mode and see what is happening.

    http://www.dofactory.com/products/net-design-pattern-framework

    http://lauteikkehn.blogspot.com/2012/03/datatable-vs-list.html

    https://dzone.com/articles/reasons-move-datatables

    Sunday, January 7, 2018 11:47 AM