如何在.net实体框架中插入或更新多个表

时间:2010-02-11 10:00:10

标签: entity-framework insert many-to-many entity-framework-4

这似乎应该是非常明显的,但实体框架的某些内容让我感到困惑,我无法让它工作。

很简单,我有三个表,Id值是标识列: 用户(userId,用户名) 类别(categoryId,categoryName) JoinTable(UserId,CategoryId)复合。

在实体设计器(这是.net 4.0)中,当我导入这些表时,正如预期的那样,连接表不会出现,但用户和类别显示关系。以下代码:

var _context = new MyContext();
var myUser = new User();
myUser.UserName = "joe";

var myCategory = new Category();
myCategory.CategoryName = "friends";

_context.Users.AddObject(myUser);  
myUser.Categories.Add(myCategory);

var saved = _context.SaveChanges();

返回错误(虽然没有添加到数据库中):

An item with the same key has already been added.

如果我在保存之前添加以下内容:

_context.Categories.AddObject(myCategory);
myCategory.Users.Add(myUser);

我得到了同样的错误,并没有保存到数据库中。如果我在尝试关联它们之前保存了myUser和myCategory对象,它们都会保存,但是第二次保存会抛出错误,没有任何内容添加到连接表中:

Cannot insert the value NULL into column 'UserId', table '...dbo.JoinTable'; column does not  allow nulls. INSERT fails. The statement has been terminated.

我显然无法理解插入了多少个关系。我错过了什么?

3 个答案:

答案 0 :(得分:5)

在将User和Category实体添加到数据库之后,您需要调用SaveChanges(),然后设置它们之间的关联。

但是,这里的真正问题是您列出的第二个例外。如果您在调试器中查看SqlProfiler或ADO.NET探查器,您将看到在第二次SaveChanges调用期间它看起来像这样:

insert [dbo].[JoinTable]([UserId]) values (@0) select [CategoryId] from
[dbo].[JoinTable] where @@ROWCOUNT > 0 and [UserId] = @0 and [CategoryId] = scope_identity()

显然,如果您正确编程了JoinTable(两列上的复合PK),这将不起作用。

如果我通过模型浏览器查看EntityModel存储,它会显示JoinTable中的CategoryId列确实将StoreGeneratedPattern设置为Identity,而UserId设置为None。为什么EF在复合PK存在的生成阶段这样做是超出我的。我将向MS发布有关此问题的错误,但同时您可以在生成后手动编辑edmx / ssdl文件以删除Identity说明符。在JoinTable的EntityType标记的Property标记下找到StoreGeneratedPattern =“Identity”字符串并将其删除:

变化:

<Property Name="CategoryId" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />

要:

<Property Name="CategoryId" Type="int" Nullable="false" />

然后,当您运行代码时,您将获得更好的插入查询(并且不再例外!):

insert [dbo].[JoinTable]([UserId], [CategoryId]) values (@0, @1)

答案 1 :(得分:1)

我这样做的方法是先用实体键生成一个有效的Category实体。

Category myCategory = _context.Categories.First(i => i.CategoryID == categoryIDToUse);

或者您可以尝试将实体创建为存根以将命中保存到数据库:

Category myCategory = new Category{CategoryID = categoryIDToUse };

然后使用AttachTo方法将该实体添加到ObjectContext上的实体集(CategorySet)(您可能想要检查它是否已经附加)。然后,您可以使用Add方法将Category添加到User实体。像这样:

myUser.Categories.Add(myCategory);

调用SaveChanges()。这对我有用。

答案 2 :(得分:0)

当新的父级添加到Context时,对象树中所有对象的状态将更改为“已添加”,因此EF会尝试将所有此类对象保存为新记录。

参考此链接: http://nileshhirapra.blogspot.in/2012/03/entity-framework-insert-operation-with.html