有没有办法减少这两个linq查询中的重复

时间:2013-01-31 18:35:53

标签: c# linq entity-framework

构建一堆报告,必须一遍又一遍地使用不同的字段做同样的事情

    public List<ReportSummary> ListProducer()
    {
        return (from p in Context.stdReports                    
                group p by new { p.txt_company, p.int_agencyId }
                    into g
                    select new ReportSummary
                    {
                        PKi = g.Key.int_agencyId,
                        Name = g.Key.txt_company,
                        Sum = g.Sum(foo => foo.lng_premium),
                        Count = g.Count()
                    }).OrderBy(q => q.Name).ToList();
    }

    public List<ReportSummary> ListCarrier()
    {
        return (from p in Context.stdReports
                group p by new { p.txt_carrier, p.int_carrierId }
                    into g
                    select new ReportSummary
                    {
                        PKi = g.Key.int_carrierId,
                        Name = g.Key.txt_carrier,
                        Sum = g.Sum(foo => foo.lng_premium),
                        Count = g.Count()
                    }).OrderBy(q => q.Name).ToList();
    }

我的思绪在如何将这两者结合在一起的空白。

3 个答案:

答案 0 :(得分:1)

看起来唯一改变的是分组参数的名称。你能编写一个包含指定分组参数的lambdas的包装函数吗?或者甚至是一个包装器函数,它接受两个字符串然后构建原始T-SQL,而不是使用LINQ?

或者,我不知道这是否会编译,您是否可以对group语句中的字段进行别名,以便始终可以以相同的方式引用分组结构,例如g.Key.id1和{{1} }?然后,您可以将分组构造传递给g.Key.id2构造函数,并在一个位置执行左手/右手分配。 (您需要将其作为动态传递,因为它是呼叫站点的匿名对象)

答案 1 :(得分:1)

你可以这样做:

public List<ReportSummary> GetList(Func<Record, Tuple<string, int>> fieldSelector)
{
    return (from p in Context.stdReports                    
        group p by fieldSelector(p)
            into g
            select new ReportSummary
            {
                PKi = g.Key.Item2
                Name = g.Key.Item1,
                Sum = g.Sum(foo => foo.lng_premium),
                Count = g.Count()
            }).OrderBy(q => q.Name).ToList();
}

然后你可以这样称呼它:

var summary = GetList(rec => Tuple.Create(rec.txt_company, rec.int_agencyId));

或:

var summary = GetList(rec => Tuple.Create(rec.txt_carrier, rec.int_carrierId));

当然,您需要将Record替换为实际返回的Context.stdReports类型。

我没有检查过是否会编译,但你明白了。

答案 2 :(得分:0)

由于两个查询之间的所有更改都是组键,因此请对其进行参数化。由于它是一个复合键(在其中有多个值),因此您需要创建一个可以保存这些值的简单类(使用通用名称)。

在这种情况下,要对其进行参数化,请将键选择器作为函数的参数。它必须是表达式和​​方法语法才能使其工作。然后,您可以将其概括为函数:

public class GroupKey
{
    public int Id { get; set; }
    public string Name { get; set; }
}

private IQueryable<ReportSummary> GetReport(
    Expression<Func<stdReport, GroupKey>> groupKeySelector)
{
    return Context.stdReports
        .GroupBy(groupKeySelector)
        .Select(g => new ReportSummary
        {
            PKi = g.Key.Id,
            Name = g.Key.Name,
            Sum = g.Sum(report => report.lng_premium),
            Count = g.Count(),
        })
        .OrderBy(summary => summary.Name);
}

然后使用适当的密钥选择器在您的查询中使用此函数。

public List<ReportSummary> ListProducer()
{
    return GetReport(r =>
        new GroupKey
        {
            Id = r.int_agencyId,
            Name = r.txt_company,
        })
        .ToList();
}

public List<ReportSummary> ListCarrier()
{
    return GetReport(r =>
        new GroupKey
        {
            Id = r.int_carrierId,
            Name = r.txt_carrier,
        })
        .ToList();
}

我不知道您为实体映射的类型,所以我做了一些假设。在你的情况下使用任何适当的东西。