【问题标题】:Efficient way to call .Sum() on multiple properties在多个属性上调用 .Sum() 的有效方法
【发布时间】:2012-07-05 07:57:20
【问题描述】:

我有一个函数,它使用 Linq 从数据库中获取数据,然后我在另一个函数中调用该函数,以使用 .Sum 对每个单独的属性求和所有单独的属性。我想知道是否有一种有效的方法可以一次汇总所有属性,而不是对每个单独的属性调用 .Sum() 。我认为我现在的做法非常缓慢(尽管未经测试)。

public OminitureStats GetAvgOmnitureData(int? fnsId, int dateRange)
    {
        IQueryable<OminitureStats> query = GetOmnitureDataAsQueryable(fnsId, dateRange);

        int pageViews = query.Sum(q => q.PageViews);
        int monthlyUniqueVisitors = query.Sum(q => q.MonthlyUniqueVisitors);
        int visits = query.Sum(q => q.Visits);
        double pagesPerVisit = (double)query.Sum(q => q.PagesPerVisit);
        double bounceRate = (double)query.Sum(q => q.BounceRate);

        return new OminitureStats(pageViews, monthlyUniqueVisitors, visits, bounceRate, pagesPerVisit);
    }

编辑

private IQueryable<OminitureStats> GetOmnitureDataAsQueryable(int? fnsId, int dateRange)
    {
        var yesterday = DateTime.Today.AddDays(-1);
        var nDays = yesterday.AddDays(-dateRange);

        if (fnsId.HasValue)
        {
            IQueryable<OminitureStats> query = from o in lhDB.omniture_stats
                                               where o.fns_id == fnsId
                                                     && o.date <= yesterday
                                                     && o.date > nDays
                                               select new OminitureStats ( 
                                                   o.page_views.GetValueOrDefault(), 
                                                   o.monthly_unique.GetValueOrDefault(),
                                                   o.visits.GetValueOrDefault(),
                                                   (double)o.bounce_rate.GetValueOrDefault()
                                               );
            return query;
        }
        return null;
    }

编辑:

public class OminitureStats
    {
        public OminitureStats(int PageViews, int MonthlyUniqueVisitors, int Visits, double BounceRate)
        {
            this.PageViews = PageViews;
            this.MonthlyUniqueVisitors = MonthlyUniqueVisitors;
            this.Visits = Visits;
            this.BounceRate = BounceRate;
            this.PagesPerVisit = Math.Round((double)(PageViews / Visits), 1);
        }

        public OminitureStats(int PageViews, int MonthlyUniqueVisitors, int Visits, double BounceRate, double PagesPerVisit)
        {
            this.PageViews = PageViews;
            this.MonthlyUniqueVisitors = MonthlyUniqueVisitors;
            this.Visits = Visits;
            this.BounceRate = BounceRate;
            this.PagesPerVisit = PagesPerVisit;
        }

        public int PageViews { get; set; }
        public int MonthlyUniqueVisitors { get; set; }
        public int Visits { get; set; }
        public double PagesPerVisit { get; set; }
        public double BounceRate { get; set; }
    }

【问题讨论】:

    标签: c# linq iqueryable


    【解决方案1】:

    IIRC 你可以一次性完成所有的求和(只要查询被翻译成 SQL)

    var sums = query.GroupBy(q => 1)
                    .Select(g => new
                    {
                        PageViews = g.Sum(q => q.PageViews),
                        Visits = g.Sum(q => q.Visits),
                        // etc etc
                    })
                    .Single();
    

    这将为您提供一个对象,其中包含作为单独属性的所有总和。

    【讨论】:

    • 谢谢乔恩。但我在var sums ... 得到NotSupportedException。但这与您的解决方案无关。因为我测试了我这样做的方式,它仍然会抛出这个异常。和IQueryable&lt;OmnitureStats&gt;部分有关系吗?
    • 您的解决方案与我的做法有何不同。我仍然必须在每个单独的属性上调用 .Sum() 。谢谢
    • @SherCoder:关于异常,您必须准确告诉我们您正在使用哪种IQueryable。关于如何更好:所有的和都表示为同一表达式树的一部分,因此 SQL 翻译层可以在一次查询中提取它们。
    • 我更新了我的问题。你可以看到我用来从表中获取数据的代码。
    • 为了我自己的利益,语义上是否与我提出的简单循环不同(嗯,我几乎可以肯定它是)?是否会因为后端执行的查询更具体而产生更高效的代码?
    【解决方案2】:

    我发现它为什么抛出NotSupportedException。我了解到Linq to Entity 不支持带参数的构造函数,因此删除了构造函数并在我的查询中进行了更改。我是一名 C# 程序员新手,如果我的解决方案可以改进,请告诉我,但目前它运行良好。

    public class OminitureStats
    {
        public int PageViews { get; set; }
        public int MonthlyUniqueVisitors { get; set; }
        public int Visits { get; set; }
        public double PagesPerVisit { get; set; }
        public double BounceRate { get; set; }
    }
    
    
    private IQueryable<OminitureStats> GetOmnitureDataAsQueryable(int? fnsId, int dateRange)
    {
        var yesterday = DateTime.Today.AddDays(-1);
        var nDays = yesterday.AddDays(-dateRange);
    
        if (fnsId.HasValue)
        {
            IQueryable<OminitureStats> query = from o in lhDB.omniture_stats
                                               where o.fns_id == fnsId
                                                     && o.date <= yesterday
                                                     && o.date > nDays
                                               select new OminitureStats() { 
                                                   o.page_views.GetValueOrDefault(), 
                                                   o.monthly_unique.GetValueOrDefault(),
                                                   o.visits.GetValueOrDefault(),
                                                   (double)o.bounce_rate.GetValueOrDefault()
                                               };
            return query;
        }
        return null;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-20
      • 1970-01-01
      • 2012-07-08
      • 1970-01-01
      相关资源
      最近更新 更多