实体框架 - 按需停止延迟加载相关实体?

lee*_*n3o 25 c# linq-to-entities entity-framework entity-framework-6

我有实体框架设置,它在我需要它的大部分时间都可以正常工作.我有这样的结构

public partial class Topic : Entity
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public DateTime CreateDate { get; set; }
    public virtual Post LastPost { get; set; }
    public virtual Category Category { get; set; }
    public virtual IList<Post> Posts { get; set; }
    public virtual IList<TopicTag> Tags { get; set; }
    public virtual MembershipUser User { get; set; }
    public virtual IList<TopicNotification> TopicNotifications { get; set; }
    public virtual IList<Favourite> Favourites { get; set; }
    public virtual Poll Poll { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我有许多相关的实体,这些实体都是列表.它们被映射为标准并且是延迟加载的,因此我可以调用Topic.Posts或Topic.TopicNotifications等...(下面的映射)

HasOptional(t => t.LastPost).WithOptionalDependent().Map(m => m.MapKey("Post_Id"));
HasOptional(t => t.Poll).WithOptionalDependent().Map(m => m.MapKey("Poll_Id"));            
HasRequired(t => t.Category).WithMany(t => t.Topics).Map(m => m.MapKey("Category_Id"));
HasRequired(t => t.User).WithMany(t => t.Topics).Map(m => m.MapKey("MembershipUser_Id"));
HasMany(x => x.Posts).WithRequired(x => x.Topic).Map(x => x.MapKey("Topic_Id")).WillCascadeOnDelete();
HasMany(x => x.TopicNotifications).WithRequired(x => x.Topic).Map(x => x.MapKey("Topic_Id")).WillCascadeOnDelete();
HasMany(t => t.Tags)
    .WithMany(t => t.Topics)
    .Map(m =>
                {
                    m.ToTable("Topic_Tag");
                    m.MapLeftKey("TopicTag_Id");
                    m.MapRightKey("Topic_Id");
                });
Run Code Online (Sandbox Code Playgroud)

这一切都很好.但有几次我需要手动填充Topic.Posts和Topic.Favorites.

但是如果我尝试设置Topic.Posts = SomeCollection它会触发延迟加载并首先加载所有帖子,然后让我设置我的集合所以我得到两组sql执行(第一个我不想要)

无论如何,是否要在我想手动设置集合时手动关闭延迟加载?

希望有意义......:/

小智 24

最好在默认情况下关闭延迟加载,而是指定何时首先加载额外数据.EF设置为允许在您的查询中使用.Include()函数进行Eager加载,如果您开始为各种功能打开/关闭延迟加载它可能会变得混乱,您最好将其关闭并管理什么/什么时候你想要数据加载,如果你觉得需要关闭它.

有关具体示例,请参阅https://msdn.microsoft.com/en-nz/data/jj574232.aspx以及您可以急切/延迟加载数据的不同方法的细分.第一个示例显示了如何从博客中提取帖子,这类似于您想要实现的内容.

var topics = context.Topics 
                      .Include(t => t.Posts) 
                      .ToList(); 
Run Code Online (Sandbox Code Playgroud)


Jer*_*vel 16

我不知道针对这个确切场景的方法,所以我必须暂时禁用/启用延迟加载.

using(var context = new MyContext())
{
    context.Configuration.LazyLoadingEnabled = false;
    // do your thing using .Include() or .Load()
    context.Configuration.LazyLoadingEnabled = true;
}
Run Code Online (Sandbox Code Playgroud)

但请注意,这是一个全局配置,因此如果在您的方案中发生这种情况,可能会出现并发问题.

  • @AllMadHare:我同意.你的解决方案要好得多. (2认同)
  • @JeroenVannevel它不是一个全局属性..至少不是在EF 6中.我想有一种方法可以全局设置它,并且配置可能是从默认/全局克隆的,但Configuration(和那个标志)是实例属性. (2认同)

小智 9

我不建议在每个请求的基础上关闭lazing加载.正如AllMadHare建议的那样,您可以完全关闭延迟加载,但这可能会强制更改加载所有数据的方式.我建议从帖子中删除虚拟关键字,以便您的类看起来像这样:

public partial class Topic : Entity
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public DateTime CreateDate { get; set; }
    public virtual Post LastPost { get; set; }
    public virtual Category Category { get; set; }
    public IList<Post> Posts { get; set; }
    public virtual IList<TopicTag> Tags { get; set; }
    public virtual MembershipUser User { get; set; }
    public virtual IList<TopicNotification> TopicNotifications { get; set; }
    public virtual IList<Favourite> Favourites { get; set; }
    public virtual Poll Poll { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

根据此处的文档:https://msdn.microsoft.com/en-us/data/jj574232.aspx#lazyOffProperty这将允许您延迟加载所有其他导航属性和急切加载帖子,如果您需要.


Mic*_*der 3

由于您使用延迟加载,因此必须为您的类和集合属性生成代理。

对我来说,用您自己的集合替换这些代理集合属性似乎是相当奇怪的设计。您失去了更改跟踪,并且很可能会产生其他一些奇怪的副作用。

我建议要么使用代理/延迟加载并放弃替换集合的想法,要么放弃使用代理并获得对生成的 POCO 类的完全控制。

这两种方法中哪一种最适合您的需求取决于您对实体框架的总体使用情况。