【问题标题】:How to avoid retrieve unwanted data that consumes extra time如何避免检索消耗额外时间的不需要的数据
【发布时间】:2019-06-02 10:55:08
【问题描述】:

我有这三个模型 A , B , C 。

假设这些类看起来像:

Public class A 
{
    public int Id {get;set;}
    public string Name {get;set;}
    public ICollection<B> bc {get;set;} 
    public ICollection<C> cc {get;set} 
}

Public class B 
{
    public int Id {get;set;}
    public string Name {get;set;}
}

Public class C  
{
    public int Id {get;set;}
    public string Name {get;set;}
}

假设我想要 A 中除 cc 或 bc 之外的所有数据。

问题是每当我调用 getall 方法时,它都会返回所有相关的内容,实际上它在我的代码中要复杂得多,所以 B 和 C 中也有集合,它带来了几乎所有的东西,而且执行起来需要很多时间,这就像一个循环。

到目前为止,我已尝试使用 select,但仍会转到模型并获取所有字段。

请帮忙,谢谢。

【问题讨论】:

    标签: asp.net entity-framework model-view-controller


    【解决方案1】:

    您可以使用数据注释从模型中排除属性。您可以访问此链接:https://docs.microsoft.com/en-us/ef/core/modeling/included-properties 以了解更多信息。希望对你有所帮助,新年快乐,我的朋友:))

    public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }
    
        [NotMapped]
        public DateTime LoadedFromDatabase { get; set; }
    }
    
    class MyContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Blog>()
                .Ignore(b => b.LoadedFromDatabase);
        }
    }
    
    public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }
    
        public DateTime LoadedFromDatabase { get; set; }
    }
    

    【讨论】:

    • 谢谢你,新年快乐。这很好,但在我的代码中的某些地方我可能需要所有数据,所以这在这种情况下不起作用
    • @michael:在你的情况下,我认为你可以使用 Automapper。对不起,我的朋友,回复晚了:))
    【解决方案2】:

    我怀疑您可能没有正确使用.Select,因为这正是它的设计目的。

    要获取相关的 A 详细信息,无需 B 或 C:

    var aDetails = context.As.Select(a => new { a.Id, a.Name }).ToList();
    

    请注意,这将返回一个匿名类型,其中仅包含您想要的字段,在本例中,是来自 A 记录的 ID 和名称。现在,如果您想返回要在视图等中使用的数据,那么您可以定义一个视图模型类来调用 AViewModel,例如使用该 ID 和名称:

    var viewModels = context.As.Select(a => new AViewModel{ Id = a.Id, Name = a.Name }).ToList();
    

    人们经常因为试图将实体发送到视图而被抓到。这是一个糟糕的、糟糕的模式,为了避免定义另一个看起来很像实体的 POCO 类,它经常被掩盖。但是,有 2 个非常好的理由应该避免它:信息的安全性和性能。 (概述here)如果你这样做:

    var results = context.As.ToList();
    

    甚至

    var results = context.As.Select(a => a).ToList();
    

    启用 LazyLoading (EF6) 这将只加载您的 A 记录,而不加载 B 或 C。但是,如果您尝试将这些实体传递回您的客户端,则序列化程序将遍历每个属性,触发 B 和 C 集合上的延迟加载,为每个单独的 A 记录加载每个集合。在返回 A 的集合时,这将比在查询中预先加载 Bs 和 Cs 的情况要糟糕得多,因为如果返回 5x A 记录,延迟加载调用将相当于:

    从 B 中选择 AId = 1,从 B 中选择 AId = 2,...

    从 C 中选择 AId = 1,从 C 中选择 AId = 2,...

    10x 额外的 SQL 语句,而不是在一个初始(更大的)SQL 语句中包含所有相关的 B 和 C 行。您可以通过关闭 EF 延迟加载(关闭代理)来避免此性能陷阱,但随后您将获得不反映实际数据状态的空集合。 (IMO 一个实体应该始终完全代表它的数据状态,不要猜测丢失的数据是否根本没有加载,或者实体实际上没有相关数据。)

    扩展Select 如何提高性能;假设您有一组订单,其中包含订单项目列表,并且每个订单都与一个客户相关联。您需要订单编号、订单项目的总成本和客户姓名。您不想为每个订单加载所有订单商品和客户详细信息:

    var orderDetails = context.Orders
        .Where(o => o.OrderDate >= startDate && o.OrderDate < endDate)
        .Select(o => new OrderViewModel
        {
            OrderId = o.OrderId,
            OrderNumber = o.OrderNumber,
            CustomerName = o.Customer.FullName,
            Total = o.OrderLines.Sum(ol => ol.UnitPrice * ol.Quantity)
        }).ToList();
    

    这是 EF 和 Linq 的一个强大功能,有助于确保数据库完成大部分工作并只返回您需要的字段。网络上的数据更少,应用服务器和客户端上的内存使用更少。

    【讨论】:

      猜你喜欢
      • 2011-10-28
      • 2018-10-27
      • 1970-01-01
      • 1970-01-01
      • 2012-01-26
      • 2020-06-18
      • 2014-04-27
      • 2013-01-20
      • 1970-01-01
      相关资源
      最近更新 更多