EF Core逻辑查询

时间:2018-10-03 14:05:26

标签: c# asp.net-core entity-framework-core

我有一个将EF Core与MVC结合使用的C#项目。

我有一个代表“虚拟”实体的控制器。通过从两个不同的表中进行选择来创建该实体,然后按月和年对每个表进行汇总,然后将两个结果连接起来。

我的问题是:是否可以(如果是,这是一个好的解决方案)用EF Core进行累加?还是我应该使用C#遍历元素并按照我想要的方式聚合它们?

编辑:目前,我可以这样做:

 public IEnumerable<MyTable> Get...(int month, int year)
        return _context.MyTable
           //.Include(b => b.)
           .Where(t => t.Month == month && t.Year == year)
           .GroupBy(a => a.BrokerId)
           .Select(param1 => new {
                                   BrokerId = param1.Key,
                                   TotalCommissionAmountBruto = param1.Sum(s => s.CommissionAmountBruto),
                                   TotalCommissionAmountNeto = param1.Sum(s=>s.CommissionAmountNeto)
                       });

这将引发错误,因为查询结果未格式化为MyTable对象。我尝试为结果创建另一个viewModel,但是没有成功(关于隐式转换的相同错误)

viewModel:

public class MyViewModel : DtoBase
{
    public int brokerId { get; set; }
    public int TotalCommissionAmountBruto { get; set; }
    public int TotalCommissionAmountNeto { get; set; }
}

2 个答案:

答案 0 :(得分:1)

有很多方法可以达到此要求。如果表之间存在父子关系,则可以使用IncludeThenInclude

您也可以使用FromSql方法运行存储过程,然后选择所需的数据。

您还可以通过扩展方式Select使用投影查询。

对于上述所有内容,您都可以参考Microsoft提供的官方文档。

答案 1 :(得分:1)

根据现在显示的代码进行编辑:

您显示的选择返回匿名类型:

.Select(param1 => new {
                         BrokerId = param1.Key,
                         TotalCommissionAmountBruto = param1.Sum(s => s.CommissionAmountBruto),
                         TotalCommissionAmountNeto = param1.Sum(s=>s.CommissionAmountNeto)
                       });

返回您的视图模型,您应该被设置为

.Select(param1 => new MyViewModel {
                                    BrokerId = param1.Key,
                                    TotalCommissionAmountBruto = param1.Sum(s => s.CommissionAmountBruto),
                                    TotalCommissionAmountNeto = param1.Sum(s=>s.CommissionAmountNeto)
                       });

然后从以下位置更改操作的返回类型:

public IEnumerable<MyTable> Get...(int month, int year)

public IEnumerable<MyViewModel> Get...(int month, int year)

然后,在您的视图中,您还必须更改模型以使用新的视图模型。

奖金-

您应该考虑返回视图模型,而不是直接将数据库模型返回到视图。视图模型有很多好处:

防止大规模分配漏洞(能够发布超出您预期的用户发布能力的漏洞)。参见

可以为每个视图量身定制它们,以允许实现视图逻辑之类的东西,这些逻辑不在数据库模型中或仅特定于该视图。

它们促进了松散耦合,从而允许视图根据数据库模型的不同需求进行更改。

提问者添加内容以显示代码之前的原始答案

您可以在EF Core中使用分组和汇总功能。看看these docs中的LINQ GroupBy示例,这是一个基本示例。它比示例显示的要复杂得多。

var query = context.Orders
    .GroupBy(o => new { o.CustomerId, o.EmployeeId })
    .Select(g => new
        {
          g.Key.CustomerId,
          g.Key.EmployeeId,
          Sum = g.Sum(o => o.Amount),
          Min = g.Min(o => o.Amount),
          Max = g.Max(o => o.Amount),
          Avg = g.Average(o => Amount)
        });

以上是分组,然后使用一些聚合函数的基本思想。

如果您已为其编写了SQL并喜欢使用它,则还可以使用EF Core call raw SQL,这乍一看似乎太局限了,因为您必须将结果映射到实体(而您不希望这样做) ')。在2.1中,他们向名为own defined modelquery types(您的虚拟实体,视图模型)添加了映射,并定义了查询。

在2.1中,您可以创建一个视图模型(您称为虚拟实体),将其添加到EF上下文中,然后可以使用数据库视图,另一个EF查询(defining query)和/对其进行查询。或匿名类型(有限制)。

例如:

给出视图模型:

public class MySpecialModel
{  
  public string Name { get; private set; }
  public int Count { get; private set; }
}

您将其添加到您的上下文中:

public DbQuery<MySpecialModel> MySpecialModel {get;set;}

然后您将其称为:

var results = context.MySpecialModel.FromSql("select name,count from a join b on b.id=a.id)

如果由于某种原因这行不通或限制太多,我建议使用像dapper这样的微型ORM,它可以获取原始SQL并将其映射到模型。

您更细微的问题对您有好处吗?

简短的回答-可能但总是检查您的ORMS结果SQL并根据需要进行相应调整。

更长的答案-在不知道查询或您现有的EF Core逻辑的复杂性以及它生成的结果SQL以及您的上下文的情况下,它必须具有多少性能,多少用户,多少次被调用等。 ..,我们无法回答。