如何避免检索消耗额外时间的不需要的数据

时间:2019-01-07 18:49:51

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

我有这三个模型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,但是仍然可以进入模型并获取所有字段。

任何帮助,请谢谢。

2 个答案:

答案 0 :(得分:0)

您可以使用数据注释从模型中排除属性。您可以访问以下链接: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; }
}

答案 1 :(得分:0)

我怀疑您可能没有正确使用.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类,经常会给它上上光。但是,有两个非常好的理由应该避免:信息的安全性和性能。 (概述here)如果您执行以下操作:

var results = context.As.ToList();

甚至

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

启用了LazyLoading(EF6),这将仅加载您的A记录,而没有B或C。但是,如果您尝试将这些实体传递回客户端,则序列化程序将遍历每个属性,从而使B和C集合的延迟加载失败,并为每个单独的A记录加载每个集合。当返回一个A的集合时,这比在查询中急于加载B和C时要差得多,因为如果返回5x A记录,则延迟加载调用将达到:

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

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

10个额外的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的强大功能,有助于确保数据库完成大部分工作并仅返回您需要的字段。网络上的数据更少,应用服务器和客户端上的内存使用更少。