【问题标题】:Save and returning newly created object while employing Service and Entity Framework 4.1?在使用 Service and Entity Framework 4.1 时保存并返回新创建的对象?
【发布时间】:2012-03-28 12:40:06
【问题描述】:

最近,我们为实体框架关闭了延迟加载和代理生成。在此之前,在我们向 EF 提交新更改后,我们将收到整个对象图。我现在正在做的是,在提交之后,我在存储库上调用 FindById 方法来取回新对象(我将导航属性放回 newley 创建的对象上)。我的问题是,这是创建后的标准做法,还是客户端应该负责再次调用服务以获取新创建的对象?

服务上的保存方法:

public SomeObject Create(SomeObject someObject)
{
     _repository.Add(someObject);
     _repository.UnitOfwork.Commit()

     //this did not exist when lazy loading and proxy generation were enabled.
     var newObject = _repository.FindById(someObject.Id);
     return newObject;

     //Before we would jsut return the created object because everything was loaded.
     //return someObject

}

我只是想知道这是否是在创建对象并禁用延迟加载和代理创建之后的最佳实践。我很想知道其他开发者是如何处理这个问题的。

【问题讨论】:

  • 我不明白你为什么要加载一个你刚刚保存并且仍然在手边的对象。如果FindById 使用与Commit 相同的上下文,newObject 将仅引用与someObject 相同的对象,该对象仍附加到上下文。我的猜测是您的问题与加载导航属性有关,但我不清楚。 FindById 是否包含 Includes 的所有导航属性,它们应该取代以前的延迟加载?
  • @Slauma,您对包含和导航属性是正确的。我确实想在提交后加载导航属性。

标签: entity-framework-4.1 service-layer


【解决方案1】:

在我们只返回创建的对象之前,因为一切都是 已加载。

不知何故,我怀疑这是真的。如果您调用SaveChanges EF 不会执行查询来加载导航属性,无论您是否使用延迟加载。例如:

假设您有一个带有客户导航引用的订单,并且数据库中已经是一个 Id = 1 的客户。现在您创建一个订单(启用延迟加载):

var order = context.Orders.Create();
order.CustomerId = 1;
context.Orders.Add(order);
context.SaveChanges();

bool isCustomerLoaded = context.Entry(order).Reference(o => o.Customer).IsLoaded;

isCustomerLoaded 将是 false - 除非客户 1 已经在上下文中,但随后该属性也将在没有延迟加载的情况下填充(“关系修复”)。当然,一旦你访问order.Customer,它就会因为延迟加载而被加载,但这是事后发生的,与SaveChanges无关。

您的代码是否是一个好主意,取决于返回对象的使用方式以及消费者的期望。通常,最接近没有延迟加载的延迟加载替代是显式加载,因为两种加载策略都执行单个查询来加载导航属性。这当然意味着您必须在消费者端引入额外的代码来加载属性,而使用延迟加载“它只是工作”时,当您使用属性并且查询发生在代理对象的重载属性 getter 的幕后。显式加载如下所示:

context.Entry(order).Reference(o => o.Customer).Load();
// or for collections
context.Entry(order).Collection(o => o.OrderItems).Load();

您必须在第一次访问导航属性的地方调用它。

如果您事先知道从您的Create 方法返回的对象将需要所有导航属性,那么您可以按照您建议的方式通过预先加载来加载它们。但这绝对是您的数据库访问模式与延迟加载相比的一个变化:急切加载只需要一个查询来加载整个对象图,但这是一个可能非常昂贵的查询,在数据库中有很多 JOIN 和许多数据回来。而延迟加载和显式加载将发出多个查询,但更简单的查询返回的数据更少。如果不考虑模型细节和进行测量,就不可能说什么更好。

【讨论】:

  • 你是对的,我写这篇文章有点匆忙,所以我为缺乏细节道歉。凭借 EF 创建的代理,我可以访问相关实体。这就是为什么我在保存更改后可以访问它们的原因。导航仅在我请求时才加载。我已经提出了一个基础架构(我将分享),以在提交或一般查询之后包含特定实体。
  • 我更想知道其他用户是否包括(在重新获取期间)或在提交后专门加载实体。使用 Reference().Load,我想知道这是否会比您所说的使用 Include() 更高效。
  • @DDiVita:我确实遇到过某些情况,即使用显式Load() 进行多个查询比使用Include 进行单个查询要快。我所知道的最极端的例子是:stackoverflow.com/a/7780935/270591(答案下方的赞成评论)。但我一般不会说Include 的性能比显式加载差。这最终是一个逐案测试的问题。经验法则也许是:如果实体上有许多导航 集合,并且可能包含 许多 元素,那么:使用 Include! 时请注意
  • 您提供的链接实际上帮助我解决了我正在处理的完全不同的查询。干杯!
猜你喜欢
  • 1970-01-01
  • 2011-12-23
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多