5

这似乎应该很明显,但是关于实体框架的一些事情让我感到困惑,我无法让它发挥作用。

很简单,我有三个表,其中 Id 值是标识列:用户 (userId, username) 类别 (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.

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

4

3 回答 3

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 文件以删除身份说明符。在 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)
于 2010-02-26T06:19:05.683 回答
1

我这样做的方法是首先使用实体​​键生成一个有效的类别实体。

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()。这对我有用。

于 2010-02-11T18:07:53.263 回答
0

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

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

于 2012-03-05T09:27:11.967 回答