I'm using EF4 with POCO and the code below is what I have to update a license. I only pasted here the section of the code that is relevant to the problem, which is adding LicenseDetails.
The problem is that for each LicenseDetail that are inserted, EF also unexpectadly adds rows to the "Item" lookup table. Why?!
The relationship of both tables defined in the database (SQLServer 2008) is shown below and I do Database first, therefore EF generates the entities' relationship based on this.
ALTER TABLE [dbo].[LicenseDetail]
WITH CHECK ADD CONSTRAINT [FK_LicenseDetail_Item] FOREIGN KEY([ItemId])
REFERENCES [dbo].[Item] ([Id])
GO
ALTER TABLE [dbo].[LicenseDetail] CHECK CONSTRAINT [FK_LicenseDetail_Item]
GO
the update method:
public static void UpdateLicense(License license)
{
using (ALISEntities context = new ALISEntities())
{
context.ContextOptions.ProxyCreationEnabled = true;
var storedLicense =
context.Licenses.Include("LicenseDetails")
.Where(o => o.Id == license.Id).SingleOrDefault();
//////////////////////////////////////////////////////////////
// license details to add
List<LicenseDetail> toAd开发者_如何学Pythond = new List<LicenseDetail>();
foreach (LicenseDetail ld in license.LicenseDetails)
{
if (storedLicense.LicenseDetails
.Where(d => d.ItemId == ld.ItemId).Count() == 0)
{
toAdd.Add(ld);
}
}
toAdd.ForEach(i => storedLicense.LicenseDetails.Add(i));
context.SaveChanges();
}
}
When you add a new LicenseDetails to context you also add Items which are referenced by those LicenseDetails. Because context doesn't know that Items already exists in the database it adds them. You need to tell context that Items are already in the database by calling context.Items.Attach(licenseDetail.Item).
You might also try using
context.Licenses.Include("LicenseDetails").Find(license.Id);
instead of
context.Licenses.Include("LicenseDetails")
.Where(o => o.Id == license.Id).SingleOrDefault();
and there is no need to use toAdd list at all - just keep adding licenseDetails in the first foreach loop.
I ended up having to issue context.ObjectStateManager.ChangeObjectState(d.Item, EntityState.Unchanged) for each LicenseDetail added. That solved the problem.
精彩评论