[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Updating LINQ, DataContext Issue

Posted on 2010-01-02
11
Medium Priority
?
767 Views
Last Modified: 2013-11-11
I'm using a generic class (that I did not write) to work with LINQ. So far, it's really working out well, but I'm having an issue updating objects.

So here is the code for retrieving an object, and also for updating it.

The issue is I'm getting an error back saying "Cannot add an entity with a key that is already in use."

I am not sure how to fix this. I think the problem is because I have this class in a DataObjects Project as the middle tier and I can't seem to figure it out. The article I got the class from claims this works with disconnected records, but I don't know how to kill off the datacontext that is in use.
public static T SelectByPK<T>(String id) where T : class
        {
            try
            {

                DataClassesDataContext context = new DataClassesDataContext();
                    

                    // get the table by the type passed in
                    var table = context.GetTable<T>();

                    // get the meta model mappings (database domain objects)
                    MetaModel modelMap = table.Context.Mapping;

                    // get the data members for this type
                    ReadOnlyCollection<MetaDataMember> dataMembers = modelMap.GetMetaType(typeof(T)).DataMembers;

                    // find the primary key field name
                    // by checking for IsPrimaryKey
                    string pk = (dataMembers.Single<MetaDataMember>(m => m.IsPrimaryKey)).Name;

                    // return a single object where the id argument
                    // matches the primary key field value
                    return table.SingleOrDefault<T>(delegate(T t)
                    {
                        String memberId = t.GetType().GetProperty(pk).GetValue(t, null).ToString();
                        return memberId.ToString() == id.ToString();
                    });
                    
            }

            catch (Exception)
            {
                throw;
            }
        }





 public static void Update<T>(T item) where T : class
        {
            try
            {
                // create a new instance of the object
                Object newObj = Activator.CreateInstance(typeof(T), new object[0]);

                PropertyDescriptorCollection originalProps = TypeDescriptor.GetProperties(item);

                // set the new object to match the passed in object
                foreach (PropertyDescriptor currentProp in originalProps)
                {
                    if (currentProp.Attributes[typeof(System.Data.Linq.Mapping.ColumnAttribute)] != null)
                    {
                        object val = currentProp.GetValue(item);
                        currentProp.SetValue(newObj, val);
                    }
                }

                

                // attach the new object to a new data context and
                // call submit changes on the context
                using (DataClassesDataContext context = new DataClassesDataContext())
                {

                    var table = context.GetTable<T>();
                    table.Attach((T)newObj, true);
                    context.SubmitChanges();
                }
            }
            catch (Exception)
            {
                throw;
            }

        }

Open in new window

0
Comment
Question by:ApexCo
  • 6
  • 5
11 Comments
 
LVL 8

Author Comment

by:ApexCo
ID: 26164528
And here is my current implementation.



var p = Repository.SelectByPK<Property>(editId);

                    p.listingTitle = txtListingTitle.Text;
                    p.status = int.Parse(dropStatus.SelectedValue);
                    p.propertyStyle = int.Parse(dropListingType.SelectedValue);
                    p.listingType = int.Parse(dropListingType.SelectedValue);
                    p.description = EditDescription.Content;
                    p.lotSize = txtLotSize.Text;
                    p.squarefeet = txtSquareFeet.Text;
                    p.bathrooms = dropBathrom.SelectedValue;
                    p.bedrooms = int.Parse(dropBedroom.SelectedValue);
                    p.address1 = txtAddress.Text;
                    p.zipcode = txtZipCode.Text;
                    p.state = int.Parse(dropState.SelectedValue);
                    p.city = int.Parse(dropCity.SelectedValue);
                    p.price = txtPrice.Text;
                    p.yearBuild = int.Parse(txtYearBuilt.Text);
                    p.GarageType = int.Parse(dropGarage.SelectedValue);
                    p.basementType = int.Parse(dropBasement.SelectedValue);
                    p.lastUpdated = DateTime.Now;

                    Repository.Update<Property>(p);

                    Response.Redirect("propertylist.aspx", false);

Open in new window

0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 26171580
I usually create a single class, with a DataContext at the root level, that is shared with every method, and property.  I don't usually have any problem with this configuration, and there is a lot of code there to sift through, in order to find a needle in a haystack...
0
 
LVL 8

Author Comment

by:ApexCo
ID: 26192027
Hi.

Well unfortunately all of the code for this is in a single class and the datacontext is at the root level along with it.

I think it's got something to do with the fact that it is in another project? But I can't seem to pin it down yet.


Thanks.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 96

Expert Comment

by:Bob Learned
ID: 26192074
You have defined a DataContext in the SelectByPK method:

    DataClassesDataContext context = new DataClassesDataContext();

Update<T> method:

    using (DataClassesDataContext context = new DataClassesDataContext())

If you have a module-level DataContext, then you don't need to create local instances inside of the methods.  Just use the module-level instance.
0
 
LVL 8

Author Comment

by:ApexCo
ID: 26289911
Tried the module level context and still receive the same error.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 26289936
When you come to the DataContext.SubmitChanges, what does the DataContext.GetChangeSet look like?
0
 
LVL 8

Author Comment

by:ApexCo
ID: 26289970
It looks exactly the same as the data I pulled back from the database, the original object and that are identical.

It seems to be ignoring any changes I have made to the fields on the add/edit page I have. If I change a textbox or dropdown value, stepping through the code shows them to be the same as their original value.


0
 
LVL 8

Author Comment

by:ApexCo
ID: 26290244
I misspoke.

I didn't do the GetChangeSet correctly, but after adding it in properly I can see I have one update. The problem is that it only updates the p.lastUpdated property, and I have no idea why.

I debug, look at the web page itself and I see the new values, but when I step through the code, the values I'm seeing are the same as the original. I went ahead and took out the class I was using and just did an attempt to directly update right from that section, and exact same results in both places.

If I change the zipcode (or anything), why is it not showing up in the code properly when I debug? Only date update applies??

DataClassesDataContext context = new DataClassesDataContext();

                    var p = context.Properties.First(x => x.propertyId == int.Parse(editId));

                    p.listingTitle = txtListingTitle.Text;
                    p.status = int.Parse(dropStatus.SelectedValue);
                    p.propertyStyle = int.Parse(dropListingType.SelectedValue);
                    p.listingType = int.Parse(dropListingType.SelectedValue);
                    p.description = EditDescription.Content;
                    p.lotSize = txtLotSize.Text;
                    p.squarefeet = txtSquareFeet.Text;
                    p.bathrooms = dropBathrom.SelectedValue;
                    p.bedrooms = int.Parse(dropBedroom.SelectedValue);
                    p.address1 = txtAddress.Text;
                    p.zipcode = txtZipCode.Text;
                    p.state = int.Parse(dropState.SelectedValue);
                    p.city = int.Parse(dropCity.SelectedValue);
                    p.price = txtPrice.Text;
                    p.yearBuild = int.Parse(txtYearBuilt.Text);
                    p.GarageType = int.Parse(dropGarage.SelectedValue);
                    p.basementType = int.Parse(dropBasement.SelectedValue);
                    p.pool = dropPool.SelectedValue;
                    p.lastUpdated = DateTime.Now;

                   //Repository.Update<Property>(p);
                    System.Data.Linq.ChangeSet cs = context.GetChangeSet();
                    context.SubmitChanges();

                    Response.Redirect("propertylist.aspx", false);

Open in new window

0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 26293985
Hmmm...diving deeper into LINQ...please wait while pressure equalizes...

I know that I have had problems with updates when I discovered the primary key column wasn't identified correctly on the .dbml designer.
Screenshot.png
0
 
LVL 8

Author Comment

by:ApexCo
ID: 26294154
I checked that as well, and it looks correct (just like your example).

Let me ask a question. I'm returning the object using the following code, and then assigning the properties of the object to their appropriate items on the aspx page.

Is there any reason to think the fields are being locked for some reason? Am I going about that the wrong way?

public void LoadProperty()
        {

            Property pEdit = Repository.SelectByPK<Property>(editId);
            txtListingTitle.Text = pEdit.listingTitle;
            dropStatus.SelectedValue = Convert.ToString(pEdit.status);
            dropPropertyStyle.SelectedValue = Convert.ToString(pEdit.propertyStyle);
            dropListingType.SelectedValue = Convert.ToString(pEdit.listingType);
            EditDescription.Content = pEdit.description;
            txtLotSize.Text = pEdit.lotSize;
            txtSquareFeet.Text = pEdit.squarefeet;
            dropBathrom.SelectedValue = Convert.ToString(pEdit.bathrooms);
            dropBedroom.SelectedValue = Convert.ToString(pEdit.bedrooms);
            txtAddress.Text = pEdit.address1;
            txtZipCode.Text = pEdit.zipcode;
            dropStatus.SelectedValue = Convert.ToString(pEdit.state);
            dropCity.SelectedValue = Convert.ToString(pEdit.city);
            txtPrice.Text = pEdit.price;
            txtYearBuilt.Text = Convert.ToString(pEdit.yearBuild);
            dropGarage.SelectedValue = Convert.ToString(pEdit.GarageType);
            dropBasement.SelectedValue = Convert.ToString(pEdit.basementType);

        }

Open in new window

0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 2000 total points
ID: 26299855
That looks like an acceptable way of getting data from the database.

Another thing to think about here is the AutoSync, ObjectTrackingEnabled and caching:

http://www.rocksthoughts.com/blog/archive/2008/01/14/linq-to-sql-caching-gotcha.aspx
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Problem Hi all,    While many today have fast Internet connection, there are many still who do not, or are connecting through devices with a slower connect, so light web pages and fast load times are still popular.    If your ASP.NET page …
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Suggested Courses

826 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question