none
How to add a database to an existing vb.net application RRS feed

  • Question

  • Hi Everyone:

    In the past I have created Visual Basic applications containing a backend database. In other words the database was an integral part of the application. The database in the application stored all the necessary data for the application to function. 

    At the time I used MS-Access. Now MS SQL Server Express is the chosen method of storage. 

    What I want to do is connect to an outside data source(Access, SQL Server, etc.) and call up a Parts database. From the parts database I am going to virtually assemble a product using a treeview control by dragging parts from the Parts database and dropping them into the treeview.

    After I have completed the virtual assembly. I will save it into a database housed inside the application I created. This way I can recall the assembly from the local database without having to be connected to the Parts database.

    Can someone point me in the proper direction?

    Thanks,


    MRM256

    Friday, October 6, 2017 8:15 PM

Answers

  • Hi Karen,

    Sorry for the delay in responding.

    I have some routines of my own for data access for both MS-Access and MS SQL Server. My problem is: I remember using VS2008 to write a application and I had to design the database for the application inside VS. Is that the case still or can I design a database in say MS-Access and use it as my back end?

    Thanks


    MRM256

    You should create and populate data in MS-Access and SQL-Server then have classes in your project to work with said data.

    For example you could have a class for MS-Access and one for SQL-Server. Each could if needed interact with each other.

    Conceptual examples

    Imports System.Data.SqlClient
    Public Class SqlServerOperations
        Private ConnectionString As String = "Data Source=KARENS-PC;Initial Catalog=NorthWindDemo;Integrated Security=True"
        Public Function Read() As DataTable
            Dim dt As New DataTable
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn, .CommandText = "TODO"}
                    cn.Open()
                    dt.Load(cmd.ExecuteReader)
                End Using
            End Using
            Return dt
        End Function
    End Class
    

    .

    Imports System.Data.OleDb
    Public Class AccessOperations
        Private Builder As New OleDbConnectionStringBuilder With
        {
            .Provider = "Microsoft.ACE.OLEDB.12.0",
            .DataSource = IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Database1.accdb")
        }
        Public Function Read() As DataTable
            Dim dt As New DataTable
            Using cn As New OleDbConnection With {.ConnectionString = Builder.ConnectionString}
                Using cmd As New OleDbCommand With {.Connection = cn, .CommandText = "TODO"}
                    cn.Open()
                    dt.Load(cmd.ExecuteReader)
                End Using
            End Using
            Return dt
        End Function
    End Class
    
    Does this make sense?


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    • Marked as answer by MRM256 Saturday, October 7, 2017 11:26 PM
    Saturday, October 7, 2017 11:20 PM
    Moderator

All replies

  • Hello,

    If the database is online from a database provider you usually get the connection string from them. Otherwise check out the following page for various connection strings for SQL-Server.

    Next up, how to work with the data high level. You can using SqlClient data provider or Entity Framework are best but there are several others that I don't recommend. 

    The class below shows the basics of working with SQL-Server with SqlClient data provider. Note that there are various ways to accomplish what is shown below, I selected this from one of my samples used to reply to questions here.

    Imports System.Data.SqlClient
    
    Public Class DataOperations
        Private CustomerDataTable As DataTable
        Public Function GetCustomers() As DataTable
            Return CustomerDataTable
        End Function
        ''' <summary>
        ''' Load data, rather than use DataTable.Load we cycle through rows else the Load method 
        ''' will mark the primary key as read-only which means no way to set the primary key and
        ''' would cause us to reload the data and set the current record.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
    
            Me.CustomerDataTable = New DataTable
            Me.CustomerDataTable.Columns.Add(New DataColumn With {.ColumnName = "Identifier", .DataType = GetType(Integer)})
            Me.CustomerDataTable.Columns.Add(New DataColumn With {.ColumnName = "CompanyName", .DataType = GetType(String)})
            Me.CustomerDataTable.Columns.Add(New DataColumn With {.ColumnName = "ContactName", .DataType = GetType(String)})
            Me.CustomerDataTable.Columns.Add(New DataColumn With {.ColumnName = "ContactTitle", .DataType = GetType(String)})
    
            Using cn As New SqlConnection With {.ConnectionString = My.Settings.ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
                    cmd.CommandText = "SELECT Identifier, CompanyName, ContactName, ContactTitle FROM [Customer] ORDER BY Identifier"
                    cn.Open()
                    Dim Reader = cmd.ExecuteReader
                    If Reader.HasRows Then
                        While Reader.Read
                            Me.CustomerDataTable.Rows.Add(New Object() {Reader.GetInt32(0), Reader.GetString(1), Reader.GetString(2), Reader.GetString(3)})
                        End While
                    End If
                End Using
            End Using
    
            Me.CustomerDataTable.AcceptChanges()
    
        End Sub
        ''' <summary>
        ''' Remove a single row from Customer table
        ''' </summary>
        ''' <param name="Identifier"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function RemoveRow(ByVal Identifier As Integer) As Boolean
            Dim Result As Boolean = False
            Using cn As New SqlConnection With {.ConnectionString = My.Settings.ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn, .CommandText = "DELETE FROM Customer WHERE Identifier = " & Identifier.ToString}
                    cn.Open()
                    Result = (cmd.ExecuteNonQuery = 1)
                End Using
            End Using
            Return Result
        End Function
        ''' <summary>
        ''' Responsible for removing more than one row.
        ''' 
        ''' Options
        '''  - pass in selected rows from the DataGridView, get identifier and do delete
        '''  - add a checkbox column, pass in rows selected and use identifier to delete
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks>
        ''' Rather than present one method of the above none are done as it shouldf be
        ''' easy enough for you the reader to implement
        ''' </remarks>
        Public Function RemoveRows() As Boolean
            Throw New NotImplementedException("TODO")
        End Function
        Private UpdateStatement As String = "UPDATE Customer SET CompanyName = @CompanyName, ContactName = @ContactName,ContactTitle = @ContactTitle WHERE Identifier = @Identifier"
        ''' <summary>
        ''' Responsible for updating rows that have 
        ''' Row.RowState = Modified
        ''' 
        ''' Use the same logic as done in the add method below.
        ''' </summary>
        ''' <param name="row"></param>
        ''' <returns></returns>
        ''' <remarks>
        ''' Once you understand the logic in add rows you will be capable
        ''' to implement this method
        ''' </remarks>
        Public Function UpdateRow(ByVal row As DataRow) As Boolean
            Dim Result As Boolean = False
            Using cn As New SqlConnection With {.ConnectionString = My.Settings.ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
                    cmd.CommandText = UpdateStatement
                    cmd.Parameters.AddWithValue("@CompanyName", row.Field(Of String)("CompanyName"))
                    cmd.Parameters.AddWithValue("@ContactName", row.Field(Of String)("ContactTitle"))
                    cmd.Parameters.AddWithValue("@ContactTitle", row.Field(Of String)("ContactTitle"))
                    cmd.Parameters.AddWithValue("@Identifier", row.Field(Of Integer)("Identifier"))
                    cn.Open()
                    Try
                        If CInt(cmd.ExecuteNonQuery) = 1 Then
                            Result = True
                        End If
                    Catch ex As Exception
                        Return False
                    End Try
                End Using
            End Using
            Return Result
        End Function
        Public Function UpdateRows(ByVal table As DataTable) As Boolean
            Throw New NotImplementedException("TODO")
        End Function
        ''' <summary>
        ''' Add new rows from the DataTable passed to us
        ''' </summary>
        ''' <param name="table"></param>
        ''' <remarks></remarks>
        Public Sub AddCustomers(ByVal table As DataTable)
            For Each row As DataRow In table.Rows
                If row.RowState = DataRowState.Added Then
                    If Not String.IsNullOrWhiteSpace(row.Field(Of String)("CompanyName")) Then
                        Dim NewIdentifier As Integer = 0
                        If AddNewCustomer(row.Field(Of String)("CompanyName"), row.Field(Of String)("ContactName"), row.Field(Of String)("ContactTitle"), NewIdentifier) Then
                            row.SetField(Of Integer)("Identifier", NewIdentifier)
                        End If
                    End If
    
                End If
            Next
            table.AcceptChanges()
        End Sub
        Private InsertStatement As String = "INSERT INTO [Customer] (CompanyName,ContactName,ContactTitle) VALUES (@CompanyName,@ContactName,@ContactTitle); SELECT CAST(scope_identity() AS int);"
        ''' <summary>
        ''' Called from AddCustomers to add a single new record
        ''' </summary>
        ''' <param name="CompanyName"></param>
        ''' <param name="ContactName"></param>
        ''' <param name="ContactTitle"></param>
        ''' <param name="NewIdentifier"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function AddNewCustomer(ByVal CompanyName As String, ByVal ContactName As String, ByVal ContactTitle As String, ByRef NewIdentifier As Integer) As Boolean
            Using cn As New SqlConnection With {.ConnectionString = My.Settings.ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
                    cmd.CommandText = InsertStatement
                    cmd.Parameters.AddWithValue("@CompanyName", CompanyName)
                    cmd.Parameters.AddWithValue("@ContactName", ContactTitle)
                    cmd.Parameters.AddWithValue("@ContactTitle", ContactTitle)
                    cn.Open()
                    Try
                        NewIdentifier = CInt(cmd.ExecuteScalar)
                        Return True
                    Catch ex As Exception
                        Return False
                    End Try
                End Using
            End Using
        End Function
        Public Function ReadSingleField(ByVal CompanyName As String) As Integer
            Dim Identifier As Integer = 0
            Using cn As New SqlConnection With {.ConnectionString = My.Settings.ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
                    cmd.CommandText = "SELECT Identifier FROM [Customer] WHERE CompanyName=@CompanyName"
                    cmd.Parameters.AddWithValue("@CompanyName", CompanyName)
                    cn.Open()
                    Identifier = CInt(cmd.ExecuteScalar)
                End Using
            End Using
    
            Return Identifier
    
        End Function
    End Class
     

    An example using Entity 

    Imports System.Data.Entity
    Imports System.Data.Entity.Infrastructure
    
    Public Class Operations
        ''' <summary>
        ''' Used to assist with filtering strings
        ''' </summary>
        Public Enum FilterOptions
            StartsWith
            Contains
            EndsWith
            Equals
        End Enum
        Public Enum ColumnFilterName
            FirstName
            LastName
        End Enum
        Public Function CustomerIdentifierList() As List(Of CustNameIdItem)
            Using entity As New DataEntities
    
                Return entity.Customers.Select(Function(cust) New CustNameIdItem With
                    {
                        .Name = String.Concat(cust.FirstName, ", ", cust.LastName),
                        .LastName = cust.LastName,
                        .Id = cust.id.ToString
                    }
                ).OrderBy(Function(cust) cust.LastName).ToList
    
            End Using
        End Function
        Public Sub Tester()
            
            Using entity As New DataEntities
                Dim AddedCustomers = entity _
                    .ChangeTracker.Entries(Of Customer) _
                    .Where(Function(cust) cust.State = EntityState.Added)
            End Using
        End Sub
        ''' <summary>
        ''' Load Customers, no Orders attached as we are using a 
        ''' DTO (Data Transfer Object) commonly used in web development.
        ''' </summary>
        ''' <returns></returns>
        Public Function LoadCustomersDTO() As List(Of CustomerDTO)
            Using entity As New DataEntities
    
                Dim ListOfCustomersDTO = entity.Customers.Select(Function(cust) _
                    New CustomerDTO With
                    {
                        .id = cust.id,
                        .FirstName = cust.FirstName,
                        .LastName = cust.LastName,
                        .Address = cust.Address,
                        .City = cust.City,
                        .State = cust.State,
                        .ZipCode = cust.ZipCode
                    }
                ).ToList
    
                Return ListOfCustomersDTO
    
            End Using
        End Function
        ''' <summary>
        ''' See if Customer exist, if not return false, if exists
        ''' then update it.
        ''' </summary>
        ''' <param name="CustomerDto"></param>
        Public Sub UpdateCustomer(ByVal CustomerDto As CustomerDTO)
    
            Try
    
                Using entity As New DataEntities
                    entity.Entry(CustomerDto.ToCustomer).State = EntityState.Modified
                    entity.SaveChanges()
                End Using
    
            Catch ex As DbUpdateConcurrencyException
                ' handle Optimistic Concurrency exception
            End Try
    
        End Sub
        ''' <summary>
        ''' Add a new customer, return the new primary key
        ''' </summary>
        ''' <param name="CustomerDto"></param>
        ''' <returns></returns>
        Public Function AddCustomer(ByVal CustomerDto As CustomerDTO) As Integer
            Using entity As New DataEntities
    
                Dim Customer As Customer = CustomerDto.ToCustomer
                entity.Entry(Customer).State = EntityState.Added
    
                '
                ' The save will bring back the new primary key
                '
                entity.SaveChanges()
                '
                ' After saving the new primary key is contained in Customer
                ' The caller in this case creates a new record in the DataGridView
                ' DataSource, a BindingSource.
                Return Customer.id
    
            End Using
        End Function
    
    
    
        Public Sub RemoveCustomer(ByVal CustomerDto As CustomerDTO)
    
            Using entity As New DataEntities
                entity.Entry(CustomerDto.ToCustomer).State = EntityState.Deleted
                entity.SaveChanges()
            End Using
    
        End Sub
    
    #Region "For use in First and Second attempt projects for demoing only"
    
        ''' <summary>
        ''' By default when there are relations to the table we want data from
        ''' they are also loaded. Place a break-point on the Console.WriteLine()
        ''' when hit examine results, note each Customer has the relation (navigation)
        ''' Orders attached.
        ''' 
        ''' Lazy loading does not help with displaying in a DataGridView
        ''' </summary>
        Public Sub LoadCustomersWithOrdersDemo()
            Using entity As New DataEntities
                Dim results = entity.Customers.ToList
                Console.WriteLine("Put break point here and examine results")
            End Using
        End Sub
        ''' <summary>
        ''' Same code as above except indicate we don't want
        ''' the relations to be attached to our Customers.
        ''' Place a break-point on the Console.WriteLine() when hit examine results,
        ''' note that the relations are not attached. But they sure are, not good
        ''' for displaying in a DataGridView unless you hide the column Order in this
        ''' case which is ICollection and will blow up when attempting to access it.
        ''' 
        ''' Lazy loading does not help with displaying in a DataGridView
        ''' </summary>
        Public Sub LoadCustomersWithoutOrdersDemo()
            Using entity As New DataEntities
                entity.Configuration.ProxyCreationEnabled = False
                Dim results = entity.Customers.ToList
                Console.WriteLine("Put break point here and examine results")
            End Using
        End Sub
        ''' <summary>
        ''' Load Customers which will have Orders attached
        ''' </summary>
        ''' <returns></returns>
        Public Function LoadCustomers() As List(Of Customer)
            Using entity As New DataEntities
                Return entity.Customers.ToList
            End Using
        End Function
    
    #End Region
    
        ''' <summary>
        ''' Provides a search for first name
        ''' </summary>
        ''' <param name="value">text to use for filter</param>
        ''' <param name="options">Type of search</param>
        ''' <remarks>
        ''' By default EF is case sensitive. Here we use ToLower to allow
        ''' case insensitive search but a fragile method is modifying the underlying table
        ''' https://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/
        ''' </remarks>
        Public Function NameFilter(ByVal ColumnName As String, ByVal value As String, ByVal options As String) As List(Of CustomerDTO)
            Dim DataSource As List(Of Customer) = New List(Of Customer)
    
            Dim ColumnNameSelection As ColumnFilterName = ColumnName.ToEnum(Of ColumnFilterName)
            Dim FilterOption As FilterOptions = options.ToEnum(Of FilterOptions)
    
            Using context As New DataEntities
                Select Case FilterOption
                    Case FilterOptions.StartsWith
                        If ColumnNameSelection = ColumnFilterName.FirstName Then
                            DataSource = context.Customers.Filter(Function(cust) cust.FirstName.ToLower().StartsWith(value.ToLower(), StringComparison.CurrentCulture)).ToList()
                        Else
                            DataSource = context.Customers.Filter(Function(cust) cust.LastName.ToLower().StartsWith(value.ToLower(), StringComparison.CurrentCulture)).ToList()
                        End If
    
                    Case FilterOptions.Contains
                        If ColumnNameSelection = ColumnFilterName.FirstName Then
                            DataSource = context.Customers.Filter(Function(cust) cust.FirstName.ToLower().Contains(value.ToLower())).ToList()
                        Else
                            DataSource = context.Customers.Filter(Function(cust) cust.LastName.ToLower().Contains(value.ToLower())).ToList()
                        End If
    
                    Case FilterOptions.EndsWith
                        If ColumnNameSelection = ColumnFilterName.FirstName Then
                            DataSource = context.Customers.Filter(Function(cust) cust.FirstName.ToLower().EndsWith(value.ToLower(), StringComparison.CurrentCulture)).ToList()
                        Else
                            DataSource = context.Customers.Filter(Function(cust) cust.LastName.ToLower().EndsWith(value.ToLower(), StringComparison.CurrentCulture)).ToList()
                        End If
    
                    Case FilterOptions.Equals
                        If ColumnNameSelection = ColumnFilterName.FirstName Then
                            DataSource = context.Customers.Filter(Function(cust) cust.FirstName.Equals(value, StringComparison.OrdinalIgnoreCase)).ToList()
                        Else
                            DataSource = context.Customers.Filter(Function(cust) cust.LastName.Equals(value, StringComparison.OrdinalIgnoreCase)).ToList()
                        End If
    
                    Case Else
                End Select
            End Using
    
            Return DataSource.Select(Function(cust) cust.ToCustomerDTO).ToList
    
        End Function
    End Class
    


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites



    Friday, October 6, 2017 10:06 PM
    Moderator
  • In the past I have created Visual Basic applications containing a backend database. In other words the database was an integral part of the application.

    Note that this is not what you were doing.  If the database was MS-Access then it was the same sort of 'backend' as the source you are now considering.   They are different database engines, they are accessed using different connection strings, and they are located differently, but they both work the same way.  There is no technical reason that one application can't use any number of different database engines - you just need to ensure that you connect to them with the appropriate connection string, and you account for any differences in the way that data is accessed (not all SQL is the same).  Depending on the actual tasks that the user undertakes, you might connect to one, the other, or both.

    Friday, October 6, 2017 10:58 PM
  • After I have completed the virtual assembly. I will save it into a database housed inside the application I created. This way I can recall the assembly from the local database without having to be connected to the Parts database.

    What  think you are referring to is a localDB or single user instance of MS SQL Server Express.

    https://blogs.msdn.microsoft.com/jerrynixon/2012/02/26/sql-express-v-localdb-v-sql-compact-edition/

    <copied>

    SQL Express User Instance

    Users familiar with today's User Instances of SQL Server Express should feel right at home with LocalDB. In essence LocalDB offers the ability to create and start a "user instance" without the hassle of installing and maintaining the parent SQL Express instance. In that respect LocalDB could be seen as an upgrade of the User Instances feature of SQL Server Express. Let me also take this opportunity to remind everyone that User Instances are on a deprecation path since SQL Server 2008.

    <end>

    https://www.youtube.com/watch?v=R2GAgr4Zlk0

    VS can create the mdf db file LocalDB that you can deploy with the application that is local to the machine.

    Saturday, October 7, 2017 5:04 AM
  • Hi Karen,

    Sorry for the delay in responding.

    I have some routines of my own for data access for both MS-Access and MS SQL Server. My problem is: I remember using VS2008 to write a application and I had to design the database for the application inside VS. Is that the case still or can I design a database in say MS-Access and use it as my back end?

    Thanks


    MRM256

    Saturday, October 7, 2017 9:40 PM
  • Hi Acamar,

    The old applications I created that used a MS-Access .MDB file for the back end relied on the old ADO database technology back in VB6. I have techniques to access MS SQL Server and MS-Access that I am currently using that use the .NET connection strings.

    When I started using VB.NET I could not use any of my old techniques due to the complete overhaul of Visual Studio. I still have heartburn, because I can no longer create a standalone executable application. Everything depends on the Framework.

    I am considering using MS-Access for data storage and retrieval on this new app I am thinking about. Just perform the save, edit, append and delete operations internally.

    Thanks,


    MRM256

    Saturday, October 7, 2017 9:55 PM
  • Hi Karen,

    Sorry for the delay in responding.

    I have some routines of my own for data access for both MS-Access and MS SQL Server. My problem is: I remember using VS2008 to write a application and I had to design the database for the application inside VS. Is that the case still or can I design a database in say MS-Access and use it as my back end?

    Thanks


    MRM256

    You should create and populate data in MS-Access and SQL-Server then have classes in your project to work with said data.

    For example you could have a class for MS-Access and one for SQL-Server. Each could if needed interact with each other.

    Conceptual examples

    Imports System.Data.SqlClient
    Public Class SqlServerOperations
        Private ConnectionString As String = "Data Source=KARENS-PC;Initial Catalog=NorthWindDemo;Integrated Security=True"
        Public Function Read() As DataTable
            Dim dt As New DataTable
            Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn, .CommandText = "TODO"}
                    cn.Open()
                    dt.Load(cmd.ExecuteReader)
                End Using
            End Using
            Return dt
        End Function
    End Class
    

    .

    Imports System.Data.OleDb
    Public Class AccessOperations
        Private Builder As New OleDbConnectionStringBuilder With
        {
            .Provider = "Microsoft.ACE.OLEDB.12.0",
            .DataSource = IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Database1.accdb")
        }
        Public Function Read() As DataTable
            Dim dt As New DataTable
            Using cn As New OleDbConnection With {.ConnectionString = Builder.ConnectionString}
                Using cmd As New OleDbCommand With {.Connection = cn, .CommandText = "TODO"}
                    cn.Open()
                    dt.Load(cmd.ExecuteReader)
                End Using
            End Using
            Return dt
        End Function
    End Class
    
    Does this make sense?


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    • Marked as answer by MRM256 Saturday, October 7, 2017 11:26 PM
    Saturday, October 7, 2017 11:20 PM
    Moderator
  • When I started using VB.NET I could not use any of my old techniques due to the complete overhaul of Visual Studio. I still have heartburn, because I can no longer create a standalone executable application. Everything depends on the Framework.

    Just so you have it straight, it is not Visual Studio that gave you heartburn. It was ADO.NET that did it. :)

     https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ado-net-overview

    I have some routines of my own for data access for both MS-Access and MS SQL Server. My problem is: I remember using VS2008 to write a application and I had to design the database for the application inside VS. Is that the case still or can I design a database in say MS-Access and use it as my back end

    VS's service based database is a MS SQL Server Express MDF file type detached from the DB engine database file.

    It should not matter what the underlying DB technology is being used in the DAL, and the BLL and UI layers don't care about the DB technology being used

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

    https://www.codeproject.com/Articles/21115/Building-an-N-Tier-Application-in-VB-NET-in-Step

    Saturday, October 7, 2017 11:46 PM