I have very limited experience using EF4. I am successfully deserializing entities from a webservice in a detached state, and I now would like to save to the database. When SaveChanges is used I get the following exception:
System.Data.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint '[Primary key constraint name]'. Cannot insert duplicate key in object '[Related Table Name]'. The duplicate key value is (1). The statement has been terminated.
the entity I am trying to save has related entities as properties and properties that are a collection of entities.
The IDs from the web service are used as the primary key for the tables, so no automatically generated ID's are used.
The following test illustrates the issue that i'm trying to resolve:
[TestMethod]
public void SaveRelatedDetachedEntitiesWithoutDuplicatesTest(){
using (var db = ProductEntities()){
//testing pre-saved existing category
if (!db.CategoryGroups.Any(e => e.Id == 3)){
db.CategoryGroups.AddObject(new Database.CategoryGroupEntity(){
Id = 3,
Name = "test group 3"
});
db.SaveChanges();
}
var categoryList = new List<CategoryEntity>(){
new CategoryEntity(){
Id = 1,
Name = "test category 1",
Groups = new List<CategoryGroupEntity> (){new CategoryGroupEntity(){
Id = 1,
Name = "test group 1"
},//duplicate
new CategoryGroupEntity(){
Id = 2,
Name = "test group 2"
}
}
},
new CategoryEntity(){
Id = 2,
Name = "test category 2",
Groups = new List<CategoryGroupEntity>{
new CategoryGroupEntity(){
Id = 1,
Name = "test group 1"
},//duplicate
new CategoryGroupEntity(){
Id = 3,
Name = "test group 3"
}//already in db
}
}
};
var product = new ProductEntity(){
Categories = categoryList,
Id = 1,
Name = "test product 1",
Type = new TypeEntity { Id = 1, Name = "test type" }
};
//all above code cannot be altered as it reflects what results from the deserialization.
db.Products.AddObject(product);
//need code here to handle the duplicates
db.SaveChanges();
var test = db.Products.Where(e => e.Id == 1).FirstOrDefault();
Assert.IsNotNull(test);
Assert.IsTrue(test.Categories.Count() == 2, "missing categories from product");
Assert.IsTrue(test.Categories.ElementAt(0).Groups.Any(e => e.Id == 1), "missing group from category 1");
Assert.IsTrue(test.Categories.ElementAt(1).Groups.Any(e => e.Id == 1), "missing group from category 2");
}
}
Your help is appreciated.
Edit: I can get a list of groups that are duplicates using the following code
var added = db.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added)
.Where(e => !e.IsRelationship).Select(e => e.Entity)
.OfType<CategoryGroupEntity>();
var duplicates = added.GroupBy(e => e.Id)
.Where(g => g.Count() > 1)
.SelectMany(g => g.Where(e => e != g.First())
Things I have tried but did not work:
-attaching entities that are duplicates to the Data Context with an unchanged state. as attaching a CategoryGroupEntity causes all related entities to be attached the duplicate key issue remains
-removing entity instances from the Categories collection and replacing them with the CategoryGroupEntity instance that was first created results in the same issue
-detaching the duplicate entity instances results in the second category losing group id 1
As a side note, I also need to avoid the duplicate key issue when a particular CategoryGroupEntity already existing in the database and an attempt is made to save an entity with the same id.
So, I need to avoid the duplicate key issue both when an entity with that ID exists both in the database or in an added state in the ObjectStateManager. the test I included above incorporates both cases.