【问题标题】:ForeignKeyReferenceAlreadyHasValueException when creating Lookups using LINQ to SQL使用 LINQ to SQL 创建查找时的 ForeignKeyReferenceAlreadyHasValueException
【发布时间】:2010-09-15 22:12:57
【问题描述】:

我是 C# 和 .NET 的新手,我刚开始学习 LINQ to SQL,我喜欢它。但是..我发现这是一件非常烦人的事情。由于“ForeignKeyReferenceAlreadyHasValueException”,实现查找非常复杂!没有简单直接的方法!我注意到,如果我删除 LINQ 实体之间的所有关联,“ForeignKeyReferenceAlreadyHasValueException”问题就不会再出现了!我正计划开发小型 WinForms 数据库应用程序,不超过 100 个表...

所以我的问题是:

如果我使用 LINQ2SQL 但删除 LINQ 实体之间的所有关联并在数据库中保留关系,我会失去什么/风险?

【问题讨论】:

  • 您能否发布使用ToLookup 并引发您提到的异常的查询之一?还要提及您在该查询中使用的哪些表/列通过外键关系相关。
  • 当我写“查找”时,我的意思是 LookUpEdit 或 ComboBox 作为一些 GridView 中的独立或 InPlace 编辑器。 (示例:设置 DataSource、DisplayMember 和 ValueMember 属性适用于 DataSet,但使用 LINQ2SQL 会引发 ForeignKeyReferenceAlreadyHasValueException)

标签: c# .net linq-to-sql


【解决方案1】:

基本上您将失去查询支持、延迟加载、IntelliSense 等。例如,如果您删除 UsersQuestions:

from u in context.Users
where u.Questions.Count > 2
select u;

LINQ 的目的是为您提供在 C# 代码中实现关系数据库模型所需的所有构造,使您能够查询该模型。如果删除所有关联/关系,LINQ to SQL 就失去了它的用途。

关于你得到的Exception

如果关联属性是 分配了一个您无法更改的值 外键字段了,你必须 通过改变来改变关系 关联属性。为了 例如,使用 Customer 和 Order from 罗斯文示例数据库。如果 订单上的“客户”属性是 分配了一个您不能再分配的值 手动更改订单的 CustomerID 字段,因为它必须匹配 PK 客户。但是,您可以 更改“客户”属性 直接给它分配一个新客户 实例。这个动作将 自动更新 CustomerID 要匹配的字段。 作者:Matt Warren(LINQ to SQL 架构师)

这是解决问题所需要做的:

LINQ to SQL ForeignKeyReferenceAlreadyHasValueException error

对于 LookUps 和 LINQ,请执行以下操作:

LINQ, Lookups, ForeignKeyReferenceAlreadyHasValueException

例如在绑定组合框时使用此代码:

With cboCategory 
.DataSource = From Category In db.Categories Order By Category.Name
              Select Category 
.DisplayMember = "Name" 
.ValueMember = "ID"    don't set value member: http://tinyurl.com/d9etoy 
.DataBindings.Add(New Binding("SelectedItem", ItemBindingSource, "Category")) 
End With 

【讨论】:

  • 能否请您详细说明最后一条评论,或许可以举个例子(比如客户 位置)以及如何绑定 LookUpEdit(DataSource、DisplayMember、ValueMember !?)
  • 查看我提供给您的最后一个链接。这实际上是评论试图告诉你的......你必须分配整个实体/对象,而不仅仅是 Id 属性。
  • 好吧,在我问这个问题之前,我已经有了......我的问题更多的是关于绑定 LookUpEdit 控件......我想我还是不明白。
【解决方案2】:

您正在以错误的方式进行这些关系更改。如果您有一个带有 Customer 对象作为成员附加到它的 Order 对象,您可以像这样查看 Customer 信息:

var order = db.Orders.Single(x => x.ID == 40);
var cusName = order.Customer.GetFullCustomerName();

但是,如果您需要在数据库中为该订单更改该客户,则不能只将 Order.CustomerID 字段设置为新 ID。这将引发 ForeignKeyReferenceAlreadyHasValueException 错误。

// wrong way...
order.CustomerID = 45; // id of the new customer
// BOOOOM goes the error here.

// right way...
order.Customer = db.Customer.Single(x => x.ID == 45);

db.SubmitChanges();

换句话说,一旦您从数据库中提取了 Order.Customer,您就不能仅通过更改 Orders 表中该行的外键来手动更改关联的客户。您必须将 order.Customer 成员设置为另一个实时 Customer 对象,然后以这种方式将您的更改回滚到数据库。

【讨论】:

    【解决方案3】:

    你失去的当然是人际关系。通常 LINQ to SQL 会自动填充抽象关系的有用集合,例如:

    var query = db.Orders.Where(o => o.Products.Count() > n);
                                       ^^^^^^^^
                               // You would lose this
    

    然后您必须以更迂回的方式编写它,例如

    var query = db.Orders.Where(o =>
                    db.OrderProducts.Count(p => p.ProductId == o.ProductId) > n);
    

    【讨论】:

    • 我明白你的意思......但是当使用 LookUpEdit 之类的控件时如何解决这个“ForeignKeyReferenceAlreadyHasValueException”(请阅读上面的 cmets)!?尽管 LINQ2SQL 易于使用且易于使用,但不能简单地绑定 LookUpEdit-s 并且总是做一些即兴创作只会让这种简单性消失!​​
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 2010-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多