Dynamically change LINQ to Entity query

int year = 2009; // get summ of TONS2009 column

var query = from ODInfo in DataContext.CIMS_TRUCKS
            where pLocationIDs.Contains(ODInfo.OID) 
            group ODInfo by ODInfo.OID into g
            select new
            {
               OID = g.Key,
               TotalTons = g.Sum( ODInfo => ODInfo.TONS2009)
            };

      

In the expression "ODInfo => ODInfo.TONS2009", how do I change TONS2009 to TONS2010 or TONS2011 based on the method parameter "int year"?

+3


source to share


5 answers


K06a's answer is close, but won't work server side. Try the following:

IEnumerable<OutputType> myQuery(IEnumerable<InputType> data, Expression<Func<InputType,decimal>> expr)
{
    return from ODInfo in DataContext.CIMS_TRUCKS
           where pLocationIDs.Contains(ODInfo.OID) 
           group ODInfo by ODInfo.OID into g
           select new OutputType
          {
              OID = g.Key,
              TotalTons = g.AsQueryable().Sum(expr)
           };
}

var query = myQuery(DataContext.CIMS_TRUCKS, ODInfo => ODInfo.TONS2009);

      

I haven't tried this, but did something similar here .

UPDATE



If you really need to translate input strings (like "2009") to expressions, it's still possible:

string year = "2009";

Type ODInfoType = typeof(ODINFOTYPE); // substitute with the type of ODInfo
ParameterExpression pe = ParameterExpression.Parameter(ODInfoType, "ODInfo");
MemberInfo mi = ODInfoType.GetProperty("TONS" + year);
MemberExpression me = Expression.MakeMemberAccess(pe, mi);
var expr = Expression.Lambda<Func<ODINFOTYPE, decimal>>(me, pe);

      

Remember, this is a patch for the extremely evil structure of your database.

+3


source


You can try something like this:

TotalTons = g.Sum( ODInfo => (year == 2009) ? ODInfo.TONS2009 : ((year == 2010) 
                                            ? ODInfo.TONS2010 : ODInfo.TONS2011))

      



Or make it more readable and use { }

to split this lambda expression into more than one line and use eg. switch.

+1


source


The best solution is to break this down into multiple queries that you can compose for the final query:

int year = 2009; // get summ of TONS2009 column

var odInfos =
   year == 2009 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2009 })
   year == 2010 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2010 })
   year == 2011 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2011 })
   : null;

var query = from ODInfo in odInfos
            where pLocationIDs.Contains(ODInfo.OID) 
            group ODInfo by ODInfo.OID into g
            select new
            {
               OID = g.Key,
               TotalTons = g.Sum(ODInfo => ODInfo.TONS)
            };

      

This will specialize in three possible runtime queries, thus providing the best performance. It's better than case-switch.

+1


source


Try this way:

IEnumerable<OutputType> myQuery(IEnumerable<InputType> data, Func<InputType,decimal> func)
{
    return from ODInfo in data
           where pLocationIDs.Contains(ODInfo.OID) 
           group ODInfo by ODInfo.OID into g
           select new OutputType
           {
              OID = g.Key,
              TotalTons = g.Sum(func)
           };
}

var query = myQuery(DataContext.CIMS_TRUCKS, ODInfo => ODInfo.TONS2009);

      

0


source


Using DynamicLinq , which also works with EF:

int year = 2009; // get summ of TONS2009 column

var query = from ODInfo in DataContext.CIMS_TRUCKS
            where pLocationIDs.Contains(ODInfo.OID) 
            group ODInfo by ODInfo.OID into g
            select g;

var projectedGroups = query.Select("new (Key as OID, Sum(TONS" + year + ") as TotalTons)");

      

0


source







All Articles