【问题标题】:Using ICollection with Entity Framework one to many, and how to improve performance将 ICollection 与 Entity Framework 一对多使用,以及如何提高性能
【发布时间】:2016-02-12 09:44:05
【问题描述】:

我最近开始在 .Net Web 应用程序中使用 EF 和 MVC,我遇到了一个问题,想看看您的想法是什么,以及您能否为我指明正确的方向。

所以,我有两个类:DataGroup 和 DataElements。一个 DataElement 可以在一个 DataGroup 中,也可以不在一个 DataGroup 中。我在 DataContext 中使用了 fluent API 来实现这一点:

    modelBuilder.Entity<DataGroup>()
            .HasMany(dg => dg.DataElements)
            .WithOptional() 
            .HasForeignKey(de => de.DataGroup_Id);

在我的 DataGroup 类中,我有以下内容:

    public virtual ICollection<DataElement> DataElements { get; set; }

    [NotMapped]
    public ICollection<DataElement> RecentDataElements //returns the last 15 data elements
    {
        get
        {
            return DataElements.OrderByDescending(de => de.GeneratedDateTime).Take(15).Reverse().ToList();
        }
    }

    [NotMapped]
    public DataElement LatestDataElement //returns the latest data element (if any)
    {
        return DataElements.OrderByDescending(de => de.GeneratedDateTime).FirstOrDefault();
    }

所以我在上面的代码中遇到的问题是,当我调用 LatestDataElement 或 RecentDataElements 时,我最终会等待相当长的时间。

我相信这是因为 DataGroup 类中的 DataElements 属性是 ICollection,RecentDataElements 和 LatestDataElement 最终导致 EF 在排序和返回子集之前将所有 DataElements 加载到内存中(可能有数千个 DataElements 在一个数据组)。

有没有办法提高效率?

我已经考虑过直接查询数据上下文而不是使用 DataElements 属性的想法,但我想看看是否还有其他选项我应该考虑。同事告诉我,将数据上下文放在模型中是不好的做法(它们是对还是错是不同的问题)。

感谢您的帮助和建议。非常感谢:)

【问题讨论】:

    标签: c# entity-framework model-view-controller


    【解决方案1】:

    简而言之:

    正如NotMapped 属性的名称已经暗示的那样,这是一个属性 linq-to-entities 不知道任何内容,并且不可能通过对数据库进行过滤来填充它。我会在你的位置做的是从你的模型中删除 Notmapped 属性并创建一个视图模型:

    public class DataGroupViewModel
    {
        public DataGroup DataGroup {get; set;}
    
        public ICollection<DataGroup> RecentDataElements {get; set;}
    }
    

    并在查询中使用投影来填充此视图:

    var result = ctx.DataGroups.Where(...).Select(d => new DataGroupViewModel
    {
        DataGroup = d;
        RecentDataElements = d.DataElements.OrderByDescending(de => de.GeneratedDateTime)
           .FirstOrDefault();
    }
    

    这当然会迫使您创建另一个模型,但这是最干净、最快的方法。你的同事也是对的, 在你的模型中进行数据库调用是一种不好的方式,模型是数据的容器,仅此而已,它不应该有逻辑来查询数据库。

    为了让它更简洁,你可以编写一些扩展方法,你可以重复使用来获取模型:

    Func<IQueryable<DataGroup>,IEnumerable<DataGroupViewModel>> GetDataGroupDTO = 
       d => d.Select(dt => new DataGroupViewModel 
       {
          DataGroup = dt;
          RecentDataElements = dt.DataElements.OrderByDescending(de => de.GeneratedDateTime)
           .FirstOrDefault();
       }
    

    然后你可以把你的查询写得更干净:

    IEnumerable<DataGroupViewModel> result = ctx.DataGroups.Where(...).GetDataGroupDTO();
    

    【讨论】:

      猜你喜欢
      • 2017-07-06
      • 2020-05-11
      • 1970-01-01
      • 2011-08-13
      • 2022-11-24
      • 2012-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多