views:

3504

answers:

7

I am doing windows appliction in vb.net. i have customer object contains save method. how do i generate insert query?

I need to save the object in relational database (SQL server). I need to know which is the correct way of doing the insertion ie,. Inside the save method i have written the SQL statement to save the object. Is it the correct way?

Thanks

+1  A: 

There's a few issues here. First, exactly where are you saving this? You say SQL, but is it a SQL Server, an instance of SQL Express, a Local Data Cache (SQL CE 3.5) or saving via a Web Service to talk to your SQL SERVER. These different data sources have different connectivity options/requirements, and in the case of SQL CE there's a few other "gotchas" involved in the SQL itself.

Second, are you sure you want to save data into a relational datastore like SQL Server? Consider, you could use XML, a data file (text, CSV. etc) or even a custom binary file type instead.

Since you're working on a windows application, you have a bunch of options on where and how to save the data. Until you know where you want to put the data, we'd be hard pressed to help you do so.

Stephen Wrighton
A: 

I need to save the object in relational database (SQL server). I need to know which is the correct way of doing the insertion ie,. Inside the save method i have written the SQL statement to save the object. Is it the correct way?

Ksmps
A: 

I'm with Stephen Wrighton. There are a LOT of variables here, and a lot of unanswered questions. If it's SQL, is it even a Microsoft dialect of SQL? Is it Oracle? MySQL? Something else?

In any event, my personal preference is to avoid building SQL in an application if I can, and invoke a stored procedure, even for inserts and updates. Then I pass the arguments for the procedure to the ADO.NET command object. I have this insane idea in my head that SQL belongs in the database. Perhaps that comes from all that time I spent debugging horrifically written ASP code that spliced SQL strings together back in the Dot Com era. (Never again.)

If you feel it's absolutely necessary to do so, meet the System.Text.StringBuilder class. Learn it. Love it. Make it your best friend.

UPDATE: Seeing your response, I see now that you are working with SQL Server. That makes things much better.

I'd recommend separating your SQL code into a separate class, away from the actual business class. Some might not agree with that, but it will keep the PURPOSE of the classes clear. (See Separation of Concerns.)

You want to have your business object handle the business logic, and a separate class that handles the work of getting data into and out of the database. That way, if you have a problem with the serialization logic, you have a far better idea of where to look, and your chances of hosing the business logic are greatly reduced. It also makes your application much easier to understand.

A little up front effort in writing a few more classes has a HUGE payoff down the road.

But that's just my opinion.

Mike Hofer
+2  A: 

A simple INSERT statement for SQL takes this basic form:

INSERT INTO [tablename] ( [column1], [column2], ... ) VALUES ( [value1], [value2], ...)

So, we obviously need to know about the database table you are using: what columns it has. We also need to know about the class: what properties it has. Finally, we need to know about the data types for the table columns and class properties, and how the properties will map to the columns. For very simple objects the names and types will just line up. But in other cases your class may itself contain a collection (or several) that would mean inserting data into more than one table.

After all this is determined, we still need two things: connection information for the database (usually distilled down into a single connection string) and whether or not you are concerned that your class instance may have been saved previously, in which case you want to build an UPDATE statement rather than INSERT.

Assuming you can answer all of that in a satisfactory manner, your VB.Net code will look something like this (of course substituting your specific column, property, type, and connection information where appropriate):

Public Class Customer
    Public Sub Save()
        DAL.SaveCustomer(Me)
    End Sub

    '   ...'

End Class

.

' a VB Module is a C# static class'
Public Module DAL 
    Private ConnString As String = "Your connection string here"

    Public Sub SaveCustomer(ByVal TheCustomer As Customer)
        Dim sql As String = "" & _
        "INSERT INTO [MyTable] (" & _
            "[column1], [column2], ..." & _
        ") VALUES (" & _
            "@Column1, @Column2, ... )"

        Using cn As New SqlConnection(ConnString), _
              cmd As New SqlCommand(sql, cn)

            cmd.Parameters.Add("@column1", SqlDbTypes.VarChar, 50).Value = TheCustomer.Property1
            cmd.Parameters.Add("@column2", SqlDbTypes.VarChar, 1000).Value = TheCustomer.Property2

            cn.Open()
            cmd.ExecuteNonQuery()
        End Using
    End Sub
End Module

I know you've already heard that separating out your database code is the "right thing to do"tm, but I thought you might also want some more specific reasons why you would want to structure your code this way:

  • Your connection string is kept in one place, so if your database server moves you only need to make one change. Even better if this is it's own assembly or config file.
  • If you ever move to a completely different database type you only need to change one file to update the program.
  • If you have one developer or a DBA who is especially good with sql, you can let him do most of the maintenance on this part of the app.
  • It makes the code for your "real" objects simpler, and therefore easier to spot when you make a logical design error.
  • The DAL code might eventually be re-usable if another application wants to talk to the same database.
  • If you use an ORM tool most of the DAL code is written for you.
Joel Coehoorn
A: 

I prefer the idea of Mike Hofer, to have a Stored Proc in the SQL Server side to handle the actual data updates, and having a separate class to wrap calls to those stored procs. Just my 0.02$

Adarsha
In my experience it depends on the system: if the database exists for use by a single application I prefer the sql code live with the application. If it's an "enterprise" database server several applications I prefer the code live with the database.
Joel Coehoorn
A: 

I agree with Mike Hofer. Keeping your class that does your retrieval and persisting of object separate from your business classes is key to having a flexible and robust design. This is the kind of code you want to be seeing in your GUI or Business layer:

//Populate Customer Objects List with data
IList<Customer> customerList = new List<Customer>()
Customer newCustomer1 = new Customer();
newCustomer.Name = "New Name"
newCustomer.email ="[email protected]"
customerList.Add(newCustomer1)

//DAL calls
DataAccessClass dalClass = new DataAccessClass ();
dalClass.InsertCustomers(customerList);

Inside your DALClass there should be a method called InsertCustomers(IList customers) and it should have the following code:

      Public Function InsertCustomers(ByVal objectList As IList(Of Customer)) As Integer
        Dim command As IDbCommand = Nothing
        Dim rowsAffected As Integer = 0
        Dim connection As IDbConnection = New System.Data.SqlClient.SqlConnection(Me.ConnectionString)
        Try 
            connection.Open
            Dim e As IEnumerator = objectList.GetEnumerator

            Do While e.MoveNext

                command = connection.CreateCommand
                command.CommandText = "insert into dbo.Customer(CustomerID,CustomerGUID,RegisterDate,Password,SiteID,Las"& _ 
                    "tName,FirstName,Email,Notes,BillingEqualsShipping,BillingLastName) values (@Cust"& _ 
                    "omerID,@CustomerGUID,@RegisterDate,@Password,@SiteID,@LastName,@FirstName,@Email"& _ 
                    ",@Notes,@BillingEqualsShipping,@BillingLastName)"
                System.Console.WriteLine("Executing Query: {0}", command.CommandText)
                Dim paramCustomerID As IDbDataParameter = command.CreateParameter
                paramCustomerID.ParameterName = "@CustomerID"
                command.Parameters.Add(paramCustomerID)
                Dim paramCustomerGUID As IDbDataParameter = command.CreateParameter
                paramCustomerGUID.ParameterName = "@CustomerGUID"
                command.Parameters.Add(paramCustomerGUID)
                Dim paramRegisterDate As IDbDataParameter = command.CreateParameter
                paramRegisterDate.ParameterName = "@RegisterDate"
                command.Parameters.Add(paramRegisterDate)
                Dim paramPassword As IDbDataParameter = command.CreateParameter
                paramPassword.ParameterName = "@Password"
                command.Parameters.Add(paramPassword)
                Dim paramSiteID As IDbDataParameter = command.CreateParameter
                paramSiteID.ParameterName = "@SiteID"
                command.Parameters.Add(paramSiteID)
                Dim paramLastName As IDbDataParameter = command.CreateParameter
                paramLastName.ParameterName = "@LastName"
                command.Parameters.Add(paramLastName)
                Dim paramFirstName As IDbDataParameter = command.CreateParameter
                paramFirstName.ParameterName = "@FirstName"
                command.Parameters.Add(paramFirstName)
                Dim paramEmail As IDbDataParameter = command.CreateParameter
                paramEmail.ParameterName = "@Email"
                command.Parameters.Add(paramEmail)
                Dim paramNotes As IDbDataParameter = command.CreateParameter
                paramNotes.ParameterName = "@Notes"
                command.Parameters.Add(paramNotes)
                Dim paramBillingEqualsShipping As IDbDataParameter = command.CreateParameter
                paramBillingEqualsShipping.ParameterName = "@BillingEqualsShipping"
                command.Parameters.Add(paramBillingEqualsShipping)
                Dim paramBillingLastName As IDbDataParameter = command.CreateParameter
                paramBillingLastName.ParameterName = "@BillingLastName"
                command.Parameters.Add(paramBillingLastName)
                Dim modelObject As Customer = CType(e.Current,Customer)
                paramCustomerID.Value = modelObject.CustomerID
                paramCustomerGUID.Value = modelObject.CustomerGUID
                paramRegisterDate.Value = modelObject.RegisterDate
                If IsNothing(modelObject.Password) Then
                    paramPassword.Value = System.DBNull.Value
                Else
                    paramPassword.Value = modelObject.Password
                End If
                paramSiteID.Value = modelObject.SiteID
                If IsNothing(modelObject.LastName) Then
                    paramLastName.Value = System.DBNull.Value
                Else
                    paramLastName.Value = modelObject.LastName
                End If
                If IsNothing(modelObject.FirstName) Then
                    paramFirstName.Value = System.DBNull.Value
                Else
                    paramFirstName.Value = modelObject.FirstName
                End If
                If IsNothing(modelObject.Email) Then
                    paramEmail.Value = System.DBNull.Value
                Else
                    paramEmail.Value = modelObject.Email
                End If
                If IsNothing(modelObject.Notes) Then
                    paramNotes.Value = System.DBNull.Value
                Else
                    paramNotes.Value = modelObject.Notes
                End If
                paramBillingEqualsShipping.Value = modelObject.BillingEqualsShipping
                If IsNothing(modelObject.BillingLastName) Then
                    paramBillingLastName.Value = System.DBNull.Value
                Else
                    paramBillingLastName.Value = modelObject.BillingLastName
                End If
                rowsAffected = (rowsAffected + command.ExecuteNonQuery)

            Loop
        Finally
            connection.Close
            CType(connection,System.IDisposable).Dispose
        End Try
        Return rowsAffected
    End Function

It is painful to write the DAL code by hand, but you will have full control of your DAL, SQL and Mapping code and changing any of those will be a breeze in the future.

If you don't feel like to write all the DAL Code by hand, you can get a CodeGenerator like Orasis Mapping Studio to generate exactly the same code shown without writing anything. You just need to build your SQL in the tool, map the properties to the paramaters and you are done. It will generate all the rest for you.

Good luck and happy DAL coding!

Ahmad
A: 

Not quite sure what the OP is asking.

You need to define exactly what you are doing in the "Save" method

  • If you are creating a new record in the Save method you need to use an INSERT statement.
  • If you are updating an existing record in the Save method then you need to use an UPDATE statement.

"Save" methods generally imply that both cases are handled by the procedure.

A better method would be to have ("Create" or "Insert") and ("Update" or "Save") methods.

Or perhaps have one procedure which handles both.