【问题标题】:Loading LINQ results into a ViewModel that has a calculated attribute (column)将 LINQ 结果加载到具有计算属性(列)的 ViewModel
【发布时间】:2017-04-26 22:04:17
【问题描述】:

我已经看到使用一个 LINQ 查询填充 ViewModel 的场景,如下所示。 问题:如何填充以下 ViewModel 的 TotalSale 属性(列) - 这是 Sale 列的总计? 注意:我使用的是最新版本的 ASP.NET Core 和 VS2015。

视图模型:

public class CategProdViewModel
{
    public string Category { get; set; }
    public string ProductName { get; set; }
    public float Sale { get; set; }
    public float TotalSale { get; set; }
}

控制器

var innerJoinQuery =  from category in categories
       join prod in products on category.ID equals prod.CategoryID
       select new CategProdViewModel { Category = category.Name, ProductName = prod.Name, Sale = prod.Sale }; 

【问题讨论】:

  • 为什么不直接设置一个字段值呢?你期望它如何计算?我在这里看不到任何 quantity 属性。附言这是如何编译的? C# 没有 real 关键字。你在使用 roslyn 转换器吗?
  • @AlexZhukovskiy 我的意思是float 在迁移期间在 SQL Server 中转换为真实的。在你指出之后,我已经纠正了错字(谢谢)。不,我没有使用任何转换器。只需简单迁移到 SQL Server 2012。
  • 好的,但是您仍然没有回答应该如何形成 GrandTotal。或者您只想在所有 CategProdViewModel 对象中复制一个值?这是可能的,但似乎是一个逻辑错误。
  • @nam 将使用分组方式形成总计,但您需要告诉我们是按 ProductName 还是按 Category 和 ProductName 还是...?
  • @AlexZhukovskiy 我们将所选类别中所选产品的详细信息显示为:CategoryName, ProductName, Sale。假设在一个会计年度内销售的总产品是 x 数。然后在带有上述列的表格中显示 x 行数,并在销售列的末尾显示该销售的总计。

标签: c# asp.net-mvc linq asp.net-core asp.net-mvc-viewmodel


【解决方案1】:

你会看到很多这样的:

public class CategProdViewModel
{
    public string Category { get; set; }
    public string ProductName { get; set; }
    public float Sale { get; set; }
    public real TotalSale { get; set; }
}

但您只会拥有最后一个属性TotalSale 一次。因此,将您的视图模型更改为:

public class CategProdViewModel
{
    public string Category { get; set; }
    public string ProductName { get; set; }
    public float Sale { get; set; }
}

为您的视图创建此模型并将其传递给您的视图。

public class UseThisOnYourView // Give it another name
{
    public List<CategProdViewModel> Items { get; set; }
    public real TotalSale { get { return this.Items.Sum(x => x.Sale); } }
}

那么你的查询会是这样的:

var innerJoinQuery =  from category in categories
       join prod in products on category.ID equals prod.CategoryID
       select new CategProdViewModel { Category = category.Name, ProductName = prod.Name, Sale = prod.Sale };

var model = new UseThisOnYourView
            { 
                Items = innerJoinQuery.ToList()
            };

注意:请记住,您需要调整视图以使用您传递给它的新类型并相应地调整代码。

【讨论】:

  • 感谢您提供另一种方法。您的代码很好,因为查询结果中没有重复 TotalSale 列。并且在性能方面可能会更好(尽管有些人可能会争辩说 sum() 函数无论如何都会在内部迭代 throw 行)。您的代码也应该使您回复的其他读者受益。
  • 它必须迭代才能得到总和。没有其他办法。但是你的模型现在更干净了,而且你没有通过网络发送这么多数据。
  • 我同意你的看法——繁重的工作是在服务器端完成的,通过网络发送的数据更少。另外,我已经更正了我的 ViewModel 上的一个小错字,您可能也想更正它 - 我的意思是在 ViewModel 中 TotalSale 的数据类型为 float
【解决方案2】:

Product的结构你不说清楚,但Sum可以有多个值

var innerJoinQuery =  from category in categories
       join prod in products on category.ID equals prod.CategoryID
       select new CategProdViewModel { 
           Category = category.Name, 
           ProductName = prod.Name, 
           Sale = prod.Sale, 
           TotalSales = products.Sum(t => t.Sale) 
};

如果没有更多关于代码的信息,很难说,而且prod.sale 可能只是最后一个产品的数量。您可以使用Sum(this IEnumerable&lt;TSource&gt; source, Func&lt;TSource, double&gt; selector) 对多个项目求和。

这是一个快速的答案。它可能需要根据其余代码的外观进行更改。也可以Group查询结果求和。

【讨论】:

  • 您建议的解决方案给了我所需的结果。但是 - 正如@CodingYoshi 在他的建议回复中所避免的那样 - 在每一行中重复TotalSales 列(尽管结果正确)。但是,在我的视图中的@foreach 语句中,我没有使用TotalSales 列——我只在最后将它用于GrandTotal。所以它有效。现在,是否使用您建议的方法或提供的@CodingYoshi 可能存在争议问题,或者可能有其他一些可能的方法。另外,您根据所提供的信息提供了建议的解决方案。
  • 是的,这绝对不是一个完整的解决方案。如果我这样做,我会Group 并将它们相加。您可能希望以这种方式检查而不是 foreach。他们都工作,这主要是偏好。很高兴你成功了。
  • 我确实必须使用 foreach,因为我在我的 cmets 到 @AlexZhukovskiy 中解释了选定类别的选定产品(来自下拉列表)的each sale 的表格行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
  • 2019-04-27
  • 2012-12-19
  • 2018-07-17
  • 1970-01-01
  • 1970-01-01
  • 2016-04-04
相关资源
最近更新 更多