I have been struggling with the following problem on Entity Framework code-first.
I have an entity class with a decimal, and I have a multiplier decimal parameter.
I want to build a query (but not to call it), which returns the entities, but the Bar
property need to be multiplied with my parameter.
From coding side:
public class Foo
{
public Guid Id { get; set; }
public Decimal Bar { get; set; }
}
// this simple stuff returns the entities after some filterings.
Context.Set<Foo>().Where(x => querying on many props).ToList();
This method is similiar what I want to achieve:
public IQueryable<Foo> GetFooQuery( .. Many properties used to the query .. , Decimal Multiplier)
{
var IQueryablePart = Context.Set<Foo>().Where(querying with the parameters);
/* ... and what to do here? ... */
/* IQueryablePart = IQueryablePart.Select(x => new {
Bar = Bar * Multiplier <-- this is okay
}); */
// but how to retrieve the other columns without listing them one by one, and how to return the data as IQueryable<Foo> ?
return IQueryablePart;
}
I would like to use this method in the following way:
IQueryable<Foo> FullQuery = null;
for(some loop, may be 10 or 1000 iterations, it depends) {
var Part = GetFooQuery(/* .. query params ..*/, 2);
if(MyFullQuery == null)
FullQuery = Part;
else
FullQuery.Union(Part);
}
// and in the end, do the db call once:
var Result = FullQuery.ToList();
In SQL, I would handle it like this:
SELECT
Id,
Bar * @MyValue as Bar,
# and all other columns
FROM
Foo
WHERE
(param queries 1) OR
(param queries 2) OR
---
(param queries N)
My question is: what is the way to do this via IQueryable
and EF? The most important, I need to call the db only one time.
I reckon it may be some query building stuff, but I'm not familiar with it yet, any help will be very appreciated.
EF6 does not support projection (select
) to a class mapped as entity. Hence the only option you have is to project to some anonymous or special class. For your scenario, the easiest I see is a class like this:
public class FooBar
{
public Foo Foo { get; set; }
public decimal Bar { get; set; }
}
Then the single query method could be like this:
public IQueryable<FooBar> GetFooQuery( .. Many properties used to the query .. , decimal multiplier)
{
return Context.Set<Foo>()
.Where(querying with the parameters)
.Select(foo => new FooBar
{
Foo = foo,
Bar = foo.Bar * multiplier
});
}
Now you can build your full query:
IQueryable<FooBar> fullQuery = null;
for (some loop, may be 10 or 1000 iterations, it depends)
{
var subQuery = GetFooQuery(/* .. query params ..*/, 2);
fullQuery = fullQuery == null ? subquery : fullQuery.Union(subQuery);
}
Note that if you use different multiplier (otherwise the whole procedure does not make sense), you'd better use LINQ Concat
method (which translates to SQL UNION ALL
) rather then Union
(which translates to SQL UNION
).
Finally, you can materialize the result as Foo
sequennce by executing the single final SQL query, switching to LINQ to Objects and converting the FooBar
to Foo
like this:
var result = fullQuery.
.AsEnumerable() // db query ends here
.Select(fooBar =>
{
fooBar.Foo.Bar = fooBar.Bar;
return fooBar.Foo;
})
.ToList();