views:

192

answers:

3

The below is a typical, for me, Update method in L2S. I am still fairly new to a lot of this(L2S & business app development) but this just FEELs wrong. Like there MUST be a smarter way of doing this. Unfortunately, I am having trouble visualizing it and am hoping someone can provide an example or point me in the right direction.

To take a stab in the dark, would I have a Person Object that has all these fields as Properties? Then what, though?

Is that redundant since L2S already mapped my Person Table to a Class?

Is this just 'how it goes', that you eventually end up passing 30 parameters(or MORE) to an UPDATE statement at some point?

For reference, this is a business app using C#, WinForms, .Net 3.5, and L2S over SQL 2005 Standard.

Here is a typical Update Call for me. This is in a file(BLLConnect.cs) with other CRUD methods. Connect is the name of the DB that holds tblPerson When a user clicks save() this is what is eventually called with all of these fields having, potentially, been updated-->

public static void UpdatePerson(int personID, string userID, string titleID, string firstName, string middleName, string lastName, string suffixID, 
                                                            string ssn, char gender, DateTime? birthDate, DateTime? deathDate, string driversLicenseNumber, 
                                                            string driversLicenseStateID, string primaryRaceID, string secondaryRaceID, bool hispanicOrigin, 
                                                            bool citizenFlag, bool veteranFlag, short ? residencyCountyID, short? responsibilityCountyID, string emailAddress, 
                                                            string maritalStatusID)
    {
        using (var context = ConnectDataContext.Create())
        {
            var personToUpdate =
                (from person in context.tblPersons
                 where person.PersonID == personID
                 select person).Single();

            personToUpdate.TitleID = titleID;
            personToUpdate.FirstName = firstName;
            personToUpdate.MiddleName = middleName;
            personToUpdate.LastName = lastName;
            personToUpdate.SuffixID = suffixID;
            personToUpdate.SSN = ssn;
            personToUpdate.Gender = gender;
            personToUpdate.BirthDate = birthDate;
            personToUpdate.DeathDate = deathDate;
            personToUpdate.DriversLicenseNumber = driversLicenseNumber;
            personToUpdate.DriversLicenseStateID = driversLicenseStateID;
            personToUpdate.PrimaryRaceID = primaryRaceID;
            personToUpdate.SecondaryRaceID = secondaryRaceID;
            personToUpdate.HispanicOriginFlag = hispanicOrigin;
            personToUpdate.CitizenFlag = citizenFlag;
            personToUpdate.VeteranFlag = veteranFlag;
            personToUpdate.ResidencyCountyID = residencyCountyID;
            personToUpdate.ResponsibilityCountyID = responsibilityCountyID;
            personToUpdate.EmailAddress = emailAddress;
            personToUpdate.MaritalStatusID = maritalStatusID;
            personToUpdate.UpdateUserID = userID;
            personToUpdate.UpdateDateTime = DateTime.Now;

            context.SubmitChanges();
        }
    }

So, if I am understanding things correctly I would have a datacontext reference in my winform UI that I would use when I populate the fields and ALSO for UPDATES, INSERTS, and DELETES. Correct?

+3  A: 

Just don't write this method :)

Any time some business logic needs to update specific fields on a person, update the specific fields on that person (and remember to update the datacontext before the http context is unloaded)

You were on the right track when you said "Is that redundant since L2S already mapped my Person Table to a Class?". Just use the class that L2S has provided :)

If you've got a (winforms) screen that needs to edit this 30 field person object, then the easiest thing to do is to databind the fields on your screen directly to the fields on linq to sql's Person object. Here's a typical screen's lifecycle:

  • Your form is constructed (with a person ID)
  • Your form's load event handler will retrieve a Person object from Linq to Sql: context.tblPersons.Single(x=>x.ID == personID)
  • This Person will be set as the form's main BindingSource's DataSource
  • A whole lot of textboxes on the screen will be setup to bind to each field on that person object, allowing the user to edit the properties directly (you can just drag a detailsview from the data sources tab onto your form in VS to do these automatically)
  • When the user hits save, just call EndEdit on the DataSource, then SubmitChanges on the L2s Datacontext

All going well, you should see new values in your database...

Rob Fonseca-Ensor
I am getting the impression that I am doing things seriously wrong. Unfortunately I am not understanding HOW to do them better. Is that what I am doing already? When the say edit-->person, then save I am passing back the potential values to save. What am I missing?
Refracted Paladin
It might pay to look at some reference apps, like MVC storefront, or scott guthrie's series of posts on Linq to SQL in ASP.NETGive us an example of when you'd call this method. Don't build the framework first, just do the minimum thing required to build your features. Even forget 3 tier for now ;)
Rob Fonseca-Ensor
Thanks, I think I am being misunderstood though. This method is in a Class file with other tblPerson CRUD methods. In my winform app a user would be looking at a Person and click EDIT, then SAVE which would trigger this call. These are all fields that are in tblPerson that could have been updated by the User in one Edit--Save call. When I look at Scott Gu's blog(http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx) or numerous other sites I see this same 'pattern'. Is my problem simply the NUMBER of fields or that I take tutorials WAY too literal?
Refracted Paladin
You keep saying something is a problem. What is the exact problem you feel you have?
Mystere Man
@Mystere Man: My original question is asking if it is 'normal', I guess, to pass all the fields like I am doing in a Update Method. I just wondered if I should use some type of object and then you pass that or...I don't know otherwise I wouldn't have asked. I am getting the feeling that what is "WRONG" is that my app allows editing of 30+ fields on a given page but I would like some input on that.
Refracted Paladin
Well, it already *IS* an object. Linq2Sql is not really an ORM, but it has ORM-like characteristics. "personToUpdate" is an object. And you have to set it's fields somehow. L2S is smart enough to only update fields that have actually changed, so there is nothing wrong with assigning them each time. It makes it simpler. Some people build a data layer with L2S, creating their own object model, others who only need crud do exactly what you're doing.
Mystere Man
@Refracted Paladin if your users require the ability to edit 30 fields on a page, then your software architecture's job is to support their needs. Business drivers trump technical constraints. I didn't realise you were building a winforms app - let me update my answer just a little...
Rob Fonseca-Ensor
I should add that databinding in WPF is much more powerful, especially when coupled with MVVM
Rob Fonseca-Ensor
+2  A: 

A DataContext follows a pattern known as a Unit of Work. It tracks all inserts, updates, and deletes you do during a piece of code.

Once that piece of code is done running, the SubmitChanges method sends all modifications to the database at one time. There is no need for you to do anything; changes you make will automatically be persisted.

Bryan Watts
Thank you, Don't I need to ASSIGN the new values to the corresponding database areas? I feel like I am missing something that everyone is taking for granted and it is causing me an extra step...
Refracted Paladin
The objects generated by L2S, in this case, `Person`, track all changes to themselves. When you write `person.FirstName = "..."`, the `Person` class detects that the value has changed, and marks *that column* for update. When you call `SubmitChanges`, all such modifications to *all* entities are sent to the database server at one time. With L2S, you do not manage inserts, updates, and deletes yourself; instead, you just act on the objects and the updates are *implied*.
Bryan Watts
@Bryan Watts: Again, thanks for your time. I am still not understanding. Aren't I doing exactly what the first half of your comment states in the above method? Where in my example am I managing or doing something 'wrong'. Hope that doesn't sound to snarky...I am just not understanding what I would be doing differntly...thanks.
Refracted Paladin
You are correct, you are populating the `person` object before saving it. I guess I didn't expect to see an `Update` method which is responsible for doing it. Instead, the code which calls that method should have access to a `DataContext`, get the `Product` instance from it, modify it, and then call `SubmitChanges`. Having the static method is superfluous; you should just update the product in the code which would otherwise call it.
Bryan Watts
Of course, this means that you can't have static methods which do inserts in real-time. You may have a reason for structuring the code that way, and in that case, what you have is reasonable. However, L2S is meant to replace methods like that. Imagine that `Update` simply took a `Product` instead of so many parameters. That would make the method more resistant to change, as now it needs to be modified if any field is added/removed/changes type. I guess a good question would be: why have the parameter list when you could send an object which has the same values?
Bryan Watts
`I guess a good question would be: why have the parameter list when you could send an object which has the same values?` This is exactly what I was trying to ask with the original question. So, if I am understanding correctly, I should have a `tblPerson` object that I pass to my Update method and my `tblPerson` should be `DataBound` to my winform, which is how the values get updated? Did I get it right or did I just fall off the bus?
Refracted Paladin
You are getting a lot closer to right. We've established that a `Person` object needs to be modified. That just leaves the actual save. Let's say you were editing the person with ID 7. At some point, you would have created a `DataContext` and queried for that person. The instance you received is attached to *that particular context*. So, if you keep a reference to the context, bind the person to the form, then do `SubmitChanges` when the user submits, there is no longer a need for the `Update` method. Getting the user, then submitting the form, is one unit of work.
Bryan Watts
+1  A: 

What is wrong with your Update method is that you have are creating a datacontext instance within it.

And I presume you also have other CRUD methods which do the same.

If you abstract your CRUD operations to a Repository class you will be using the DataContext as it was meant to be used.

See the answer to this question, if you follow the design outlined you will be just passing a Person object to the repository Update method and it will not be so unwieldy.

Nicholas Murray