Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to reduce duplication in these two linq queries

Building a bunch of reports, have to do the same thing over and over with different fields

    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();
    }

My Mind is drawing a blank on how i might be able to bring these two together.

like image 725
MarkKGreenway Avatar asked Jan 31 '13 18:01

MarkKGreenway


2 Answers

It looks like the only thing that changes are the names of the grouping parameters. Could you write a wrapper function that accepts lambdas specifying the grouping parameters? Or even a wrapper function that accepts two strings and then builds raw T-SQL, instead of using LINQ?

Or, and I don't know if this would compile, can you alias the fields in the group statement so that the grouping construct can always be referenced the same way, such as g.Key.id1 and g.Key.id2? You could then pass the grouping construct into the ReportSummary constructor and do the left-hand/right-hand assignment in one place. (You'd need to pass it as dynamic though, since its an anonymous object at the call site)

like image 134
Seth Petry-Johnson Avatar answered Nov 14 '22 22:11

Seth Petry-Johnson


You could do something like this:

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();
}

And then you could call it like this:

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

or:

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

Of course, you'll want to replace Record with whatever type Context.stdReports is actually returning.

I haven't checked to see if that will compile, but you get the idea.

like image 22
itsme86 Avatar answered Nov 14 '22 22:11

itsme86