ApexCo
asked on
Updating LINQ, DataContext Issue
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.
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;
}
}
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...
ASKER
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.
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.
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.
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.
ASKER
Tried the module level context and still receive the same error.
When you come to the DataContext.SubmitChanges, what does the DataContext.GetChangeSet look like?
ASKER
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.
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.
ASKER
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??
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);
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
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
ASKER
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?
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);
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Open in new window