实体框架 - 连接新添加的 Poco 实体并加载子对象(插入/添加)
Posted
技术标签:
【中文标题】实体框架 - 连接新添加的 Poco 实体并加载子对象(插入/添加)【英文标题】:Entity Framework - Connect Newly Added Poco Entity And Load Child Objects (Insert/Add) 【发布时间】:2013-06-29 00:25:34 【问题描述】:我想知道是否可以连接新创建的(poco)实体添加到 DbContext(以便子对象可以在导航时延迟加载)
var user = new User();
user.LocationID = 3;
dbContext.Users.Add(user);
var locationName = user.Location.Name;
(注意:我明白我可以直接获取Location对象并赋值,上面的例子只是为了这个问题的目的)
(注二:我可以创建一个代理对象然后复制值,这样的对象将被连接(并进行延迟加载)但任何复杂的子对象(其他 pocos)都不会包含在副本中)
有没有办法连接(或加载)添加的 poco?
【问题讨论】:
这很有趣,我很惊讶上面的方法不起作用(因为你是延迟加载)也许你需要先保存更改? @LukeMcGregor 是的,一旦您 SaveChanges 对象已连接。但是我正在尝试在保存之前使用该对象。 这只是推测,但可能是由于验证,如果您实际上没有将该行提交到数据库,您实际上并不知道 FK 是否存在。 @LukeMcGregor 是有道理的,但是当在同一场景中使用新代理(而不是 poco)时,子属性会延迟加载(即使对于新实体) 【参考方案1】:简短的回答是,在使用外键和 POCO 时,您可以在设置 FK 后显式延迟加载引用属性,如下所示:
context.Entry(e).Reference(propName).Load();
如果您需要经常遍历对象图,那么值得考虑的是,在概念级别上工作而不是使用外键属性对您来说更容易。
当上下文跟踪由导航属性表示的实体时,可以在 DetectChanges() 上同步 FK 和导航属性。 documentation 表明这仅在对象具有永久键时发生。
如果参考处于添加状态(在本例中,课程 对象),参考导航属性将不同步 使用新对象的键值,直到调用 SaveChanges。 同步不会发生,因为对象上下文没有 包含已添加对象的永久密钥,直到它们被保存。
但是,文档似乎不正确或具有误导性,当使用处于Added
状态且没有永久键的新添加实体的属性时,导航属性和外键的同步仍然会发生。
下面是我用来调查此问题的我自己的数据模型上的一些测试代码。这是将 EF5 与 .Net4 一起使用,据我所知实际上是 EF4.3。
using (MyContext context = new MyContext())
/*
* Uncomment these lines to test assigning FK Id when entity is being tracked
*/
Customer cust1 = context.Customers.OrderBy(x => x.Id).First();
Customer cust2 = context.Customers.OrderBy(x => x.Id).Skip(1).First();
/*
* Uncomment these lines to test assigning FK Id
* without having entity loaded in ObjectStateManager
*/
//Customer cust1 = context.Customers.AsNoTracking().OrderBy(x => x.Id).First();
//Customer cust2 = context.Customers.AsNoTracking()
// .OrderBy(x => x.Id).Skip(1).First();
//new entities
Quote proxyQ = context.Quotes.Create();
Quote pocoQ = new Quote();
/*
* if adding the new entities to context before setting FK properties
* DetectChanges must be called later to attempt sync with nav props
*/
context.Quotes.Add(proxyQ);
context.Quotes.Add(pocoQ);
//set FK Customer ids
proxyQ.CustomerId = cust1.Id;
pocoQ.CustomerId = cust2.Id;
/*
* FK / nav prop sync happens on DetectChanges() if the Customer
* entity is being tracked
* it must be explicitly called if it has not been called using
* one of the AutoDetectChanges functions in order to sync
*/
context.ChangeTracker.DetectChanges();
/*
* Alternatively, if the new entities are added to context after setting FK props
* and AutoDetectChanges is enabled then DetectChanges is called implicitly and
* FK / nav prop sync will happen here if the matching Customer entity is
* being tracked by the context.
*/
//context.Quotes.Add(proxyQ);
//context.Quotes.Add(pocoQ);
/*
* If assigning FK Id and the entity the id represents is not tracked then
* proxy will lazy load Customer here.
*/
Console.WriteLine("Proxy quote with key 0 linked to customer with name 1",
proxyQ.Id.ToString(), proxyQ.Customer != null ? proxyQ.Customer.Name : "null");
/*
* Obviously no lazy loading of Customer can occur here for a POCO
*/
Console.WriteLine("POCO quote with key 0 linked to customer with name 1",
pocoQ.Id.ToString(), pocoQ.Customer != null ? pocoQ.Customer.Name : "null");
/*
* But we can explicit lazy load when using POCO if we have assigned
* an FK Customer Id to a POCO quote and the Customer entity is not
* being tracked by context
*/
//context.Entry(pocoQ).Reference("Customer").Load();
//Console.WriteLine("POCO quote with key 0 linked to customer with name 1",
// pocoQ.Id.ToString(), pocoQ.Customer != null ? pocoQ.Customer.Name : "null");
【讨论】:
感谢您的链接,但是当您创建一个新的代理 (_dbContext.Users.Createcontext.Entry(e).Reference(propName).Load();
以上是关于实体框架 - 连接新添加的 Poco 实体并加载子对象(插入/添加)的主要内容,如果未能解决你的问题,请参考以下文章
将 POCO/实体添加到 DbContext 以进行自定义查询/过程,而无需先在实体框架代码中创建表