gpt4 book ai didi

entity-framework-5 - EF 5.0 新对象 : assign foreign key property does not set the foreign key id, 或添加到集合

转载 作者:行者123 更新时间:2023-12-01 12:48:05 25 4
gpt4 key购买 nike

EF 5.0,在现有数据库工作流上使用代码优先。数据库有基本的 SalesOrder 和 SalesOrderLine 表,在 SalesOrderLine 上需要外键,如下所示;

public class SalesOrder
{
public SalesOrder()
{
this.SalesOrderLines = new List<SalesOrderLine>();
}

public int SalesOrderID { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }

public virtual ICollection<SalesOrderLine> SalesOrderLines { get; set; }
}

public class SalesOrderLine
{
public SalesOrderLine()
{
}
public int SalesOrderLineID { get; set; }
public int SalesOrderID { get; set; }

public virtual SalesOrder SalesOrder { get; set; }
}
public SalesOrderLineMap()
{
// Primary Key
this.HasKey(t => t.SalesOrderLineID);
// Table & Column Mappings
this.ToTable("SalesOrderLine");
this.Property(t => t.SalesOrderLineID).HasColumnName("SalesOrderLineID");
this.Property(t => t.SalesOrderID).HasColumnName("SalesOrderID");

// Relationships
this.HasRequired(t => t.SalesOrder)
.WithMany(t => t.SalesOrderLines)
.HasForeignKey(d => d.SalesOrderID);
}

现在根据这个页面: http://msdn.microsoft.com/en-us/data/jj713564

...我们被告知:

The following code removes a relationship by setting the foreign key to null. Note, that the foreign key property must be nullable.

course.DepartmentID = null;

Note: If the reference is in the added state (in this example, the course object), the reference navigation property will not be synchronized with the key values of a new object until SaveChanges is called. Synchronization does not occur because the object context does not contain permanent keys for added objects until they are saved. If you must have new objects fully synchronized as soon as you set the relationship, use one of the following methods.

By assigning a new object to a navigation property. The following code creates a relationship between a course and a department. If the objects are attached to the context, the course is also added to the department.Courses collection, and the corresponding foreign key property on the course object is set to the key property value of the department.

course.Department = department;

...我觉得不错!

现在我的问题:我有以下代码,但两个断言都失败了 - 为什么?

    using (MyContext db = new MyContext ())
{
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();
sol.SalesOrder = so;

Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));
}

两个对象都附加到上下文 - 不是吗?我需要做一个 SaveChanges() 才能工作吗?如果是这样,这似乎有点愚蠢,而且当一个新对象被添加到外键集合时,我需要手动设置对象的所有引用,这很烦人。

-- 更新--

我应该将 Gert 的回答标记为正确,但我对此不是很满意,所以我会等一两天。 ...原因如下:

以下代码也不起作用:

SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();
db.SalesOrderLines.Add(sol);

sol.SalesOrder = so;
Trace.Assert(so.SalesOrderLines.Contains(sol));

唯一工作的代码是这样的:

SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();

sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);

Trace.Assert(so.SalesOrderLines.Contains(sol));

...换句话说,您必须先设置所有外键关系,然后调用 TYPE.Add(newObjectOfTYPE)在连接任何关系和外键字段之前。这意味着从完成 Create 到执行 Add(),对象基本上处于半生不熟的状态。我曾(错误地)认为自从我使用了 Create(),并且由于 Create() 返回了一个子类动态对象(而不是使用返回 POCO 对象的“new”),关系连接将被处理我。对我来说也很奇怪,您可以在使用 new 运算符创建的对象上调用 Add() 并且它会起作用,即使该对象不是子类类型...

换句话说,这会起作用:

    SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = new SalesOrderLine();

sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);

Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));

...我的意思是,这很酷,但它让我想知道;使用“Create()”而不是 new 有什么意义,如果在任何一种情况下您都需要 Add() 对象(如果您希望它正确附加)?

最令我恼火的是以下失败;

SalesOrder so = db.SalesOrders.OrderBy(p => p.SalesOrderID).First();
SalesOrderLine sol = db.SalesOrderLines.Create();

sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);

// NOTE: at this point in time, the SalesOrderId field has indeed been set to the SalesOrderId of the SalesOrder, and the Asserts will pass...
Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));

sol.SalesOrder = db.SalesOrders.OrderBy(p => p.SalesOrderID).Skip(5).First();

// NOTE: at this point in time, the SalesOrderId field is ***STILL*** set to the SalesOrderId of the original SO, so the relationships are not being maintained!
// The Exception will be thrown!
if (so.SalesOrderID == sol.SalesOrderID)
throw new Exception("salesorderid not changed");

...这对我来说完全是废话,让我觉得 EntityFramework,即使是第 5 版,也像是宣纸桥上的雷区。为什么上面的代码无法在第二次分配 SalesOrder 属性时同步 SalesOrderId?我在这里缺少什么基本技巧?

最佳答案

我找到了我要找的东西! (并在此过程中学到了很多东西)

认为 EF 在其动态代理中生成的是“更改跟踪代理”。这些代理类的行为更像是从 ADO.Net 实体数据模型派生的旧 EntityObject 部分类。

通过对动态生成的代理类进行一些反射(reflection)(感谢我在这篇文章中找到的信息:http://davedewinter.com/2010/04/08/viewing-generated-proxy-code-in-the-entity-framework/),我看到我的关系属性的“获取”被覆盖以进行延迟加载,但是“set”根本没有被覆盖,所以当然在 DetectChanges 被调用之前什么也没有发生,并且 DetectChanges 使用“与快照比较”方法检测变化。

进一步挖掘最终将我引向这对非常有用的帖子,我向所有使用 EF 的人推荐它们: http://blog.oneunicorn.com/2011/12/05/entity-types-supported-by-the-entity-framework/

http://blog.oneunicorn.com/2011/12/05/should-you-use-entity-framework-change-tracking-proxies/

不幸的是,为了让 EF 生成更改跟踪代理,必须发生以下情况(引用自上文):

  • The rules that your classes must follow to enable change-tracking proxies are quite strict and restrictive. This limits how you can define your entities and prevents the use of things like private properties or even private setters. The rules are: The class must be public and not sealed. All properties must have public/protected virtual getters and setters. Collection navigation properties must be declared as ICollection<T>. They cannot be IList<T>, List<T>, HashSet<T>, and so on.

  • Because the rules are so restrictive it’s easy to get something wrong and the result is you won’t get a change-tracking proxy. For example, missing a virtual, or making a setter internal.

...他继续提到有关更改跟踪代理的其他事情,以及为什么它们可能表现出更好或更差的性能。

在我看来,更改跟踪代理类会很好,因为我来自 ADO.Net 实体模型世界,而且我已经习惯了以这种方式工作,但我也有一些相当丰富的类,我不确定我是否能够满足所有标准。此外,第二个要点让我相当紧张(尽管我想我可以创建一个循环遍历我所有实体的单元测试,对每个实体执行 Create(0,然后测试 IEntityWithChangeTracker 接口(interface)的结果对象)。

在我原来的例子中,通过将我所有的属性设置为虚拟,我确实得到了 IEntityWithChangeTracker 类型的代理类,但我觉得有点......我不知道......“脏”......使用它们,所以我想我只需要接受它并记住在做作业时总是设置我的关系的双方。

无论如何,感谢您的帮助!

干杯,克里斯

关于entity-framework-5 - EF 5.0 新对象 : assign foreign key property does not set the foreign key id, 或添加到集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14183423/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com