In EF, when you want to include a navigation property in the result of a query, you use Include(). Since some queries require calling this more than once, I tried to create a generic wrapper around this concept:
public IQueryable<T> FindAll<P>(params Expression<Func<T, P>>[] predicates) where P : class {
var entities = AllEntities();
foreach (var p in predicates) entities = entities.Include(p);
return entities;
}
And call it as such:
var customers = FindAll(q => q.Orders, q => q.Invoices, q => q.Contacts);
Questions:
The function compiles, but when I call it: "The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly." What am I doing wrong?
If I get it to work, can I call Include() the first time: var customers = FindAll(q => q.Orders, q => q.Invoices); and then again later in a separate step: customers = customers.Include(p => p.Invoices); or will that result in poor performance such that I should do the includes in one go?
EDIT:
JonSkeet's answer is correct, of course, and yet there is this solution which seems to do what I want. Not sure why it works however. Is it because of the Aggregate() function?
Fundamentally, I think you've got a problem - assuming that q.Orders, q.Invoices and q.Contacts return different types, you can't express what you want to happen. You probably want something like:
entities.Include<Parent, Order>(p => p.Order);
entities.Include<Parent, Invoice>(p => p.Invoices);
entities.Include<Parent, Contact>(p => p.Contacts);
... so you want a different value for P for each predicate. But you're calling a single method, providing a single type argument for P.
It's not clear that this is really giving you much benefit anyway... couldn't you just write:
var customers = AllEntities().Include(q => q.Orders)
.Include(q => q.Invoices)
.Include(q => q.Contacts);
I'd say that's clearer and it gets round the "multiple type parameters" problem.
Related
That's my code:
ProjetoTipoCargaModelo projAux =
dbContext.ProjetoTipoCargaDbSet.Find(idProjetoTipoCarga);
ICollection<ProjetoTipoCargaRegraModelo> regras =
projAux.ListaRegra.Where(x => x.Ativo).ToList();
IQueryable<ProjetoTipoCargaRegraModelo> pr =
dbContext.ProjetoTipoCargaDbSet.Select(
x => regras.FirstOrDefault(y => y.IdProjetoTipoCarga == x.IdProjetoTipoCarga));
var projetoCompleto = pr.
Include(x => x.ListaRegraLiberacaoInicioViagem).
Include(x => x.ListaRegraTecnologiaAceita).
Include(x => x.RegraAreaSombra).
Include(x => x.RegraAtuadorNecessario)
It's showing an error at first include, but I'm trying to do it on Iquerable object!
What's wrong where?
My problem is make this include in a filtered set of results.
[Edit]
Error:
Cannot convert lambda expression to type 'string' because it is not a delegate type
It's not a runtime error, it's a compilation error.
[Edit 2]
My usings:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
[Edit 3]
Answer:
ICollection<ProjetoTipoCargaRegraModelo> regras = projAux.ListaRegra.Where(x => x.Ativo).ToList();
IQueryable<ProjetoTipoCargaModelo> pr = dbContext.ProjetoTipoCargaDbSet.Where(x => x.IdProjetoTipoCarga == regras.FirstOrDefault(y => y.IdProjetoTipoCarga == x.IdProjetoTipoCarga).IdProjetoTipoCarga);
var projetoCompleto = pr.
Include(x => x.ListaRegraLiberacaoInicioViagem).
Include(x => x.ListaRegraTecnologiaAceita).
Include(x => x.RegraAreaSombra).
The .Include() method only works on ObjectQuery<TEntity>
Try:
context.EntitySet.Include(...).Select(...)
instead of:
context.EntitySet.Select(...).Include(...)
or use an extenion method like this:
public static class MyExtensions
{
public static IQueryable<TEntity> Include<TEntity>(
this IQueryable<TEntity> query, string path)
{
var efQuery = query as ObjectQuery<TEntity>;
if (efQuery == null)
return query;
return efQuery.Include(path);
}
}
or better yet, use the already available extension method that supports lambda expressions instead of strings as paths.
Also, do not use so many includes unless most are 1:1 or :1 relationships, 1: (or :) relationships greatly increase the IO from the database, resulting in bad performance.
Consider using multiple queries with .Future() to enable a single access to the database instead.
It's not related to the Includes.
You can't use regas in a LINQ-to-entities query because it's an ICollection. EF can't translate that into SQL.
Your "answer" can't possibly work with EF. The object regas is an in-memory list of Regra entities (I guess). If you use that directly in...
var pr = dbContext.ProjetoTipoCargaDbSet
.Where(x => x.IdProjetoTipoCarga == regras.FirstOrDefault(y => y.IdProjetoTipoCarga == x.IdProjetoTipoCarga).IdProjetoTipoCarga);
...you should get an exception like
Unable to create a constant value of type 'Regra'. Only primitive types or enumeration types are supported...
But, boy, what a tortuous way to get where you want to be! First you get a ProjetoTipoCargaModelo object by an idProjetoTipoCarga. Then you fetch its active Regras. Then you basically use the IdProjetoTipoCarga values of the Regras to see if one of them is equal to the original idProjetoTipoCarga and if so, you use its value to get a ProjetoTipoCargaModelo object.
If you remove all the redundancies, what's left is:
var pr = dbContext.ProjetoTipoCargaDbSet
.Where(x => x.IdProjetoTipoCarga == idProjetoTipoCarga
&& x.ListaRegra.Any(r => r.Ativo));
I you us this LINQ statement, you append your includes to pr.
I'm having issues trying to reuse ProjectionLists in NHibernate QueryOvers. I can't work out how to reuse things for different root entities.
Object model is roughly represented as:
Breakfast one to many Pastry many to zero-or-one Coffee
The two separate queries are roughly:
session.QueryOver<Breakfast>()
.Where(b => b.Id == searchId)
.Inner.JoinQueryOver(b => b.Pastries, () => pastry)
.Left.JoinAlias(p => p.Coffee, () => coffee)
.Select(projections)
.TransformUsing(Transformers.AliasToBean<TargetDto>())
.List<TargetDto>();
session.QueryOver<Coffee>()
.Where(c => c.Id == searchId)
.Inner.JoinQueryOver(c => c.Pastries, () => pastry)
.Select(projections)
.TransformUsing(Transformers.AliasToBean<TargetDto>())
.List<TargetDto>();
The common projections I'm trying to reuse looks like this:
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => pastry.Name, () => target.PastryName))
.Add(Projections.Property(() => coffee.Name, () => target.CoffeeName));
These projections, using the aliases, work fine for the first query (root: Breakfast), because they're not trying to pull off properties that are on that root entity. On the second query (root: Coffee), it explodes saying it can't find 'coffee.Name' on Coffee, because it doesn't like the alias. The QueryOver(() => coffee) syntax doesn't help because it doesn't actually register 'coffee' as an alias, it just uses it for type inference. Oh bloody hell that was the problem. There's a stupid piece of application infrastructure that is breaking the alias syntax to not actually use the alias version underneath.
The second query wants the projections to look like:
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => pastry.Name, () => target.PastryName))
.Add(Projections.Property<Coffee>(c => c.Name, () => target.CoffeeName));
However this is now incompatible with the first query.
Is there any way of making this work, so the I can project properties without knowing what the root entity type is?
I think all you need to do is assign the coffee alias in the session.QueryOver<Coffee> call:
Coffee coffee = null;
session.QueryOver<Coffee>(() => coffee)
/* etc */
The below might be completely unrelated to what you're doing, but I figured I'd include it in case anyone else is writing code that passes around QueryOver aliases.
I'd add a word of caution-- reusing aliases across different queries like this can be a little dangerous.
NHibernate takes the expression () => coffee and grabs the name of the alias you're using from the expression (in this case, "coffee") and then uses it in the generated SQL as an alias. This means that depending on how your code is structured, shared projections like this could break if alias names change.
For example, say you had the following method to return some shared projections:
public ProjectionList GetSharedProjections()
{
Coffee coffee = null;
TargetDTO target;
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => coffee.CoffeeName)
.WithAlias(() => target.CoffeeName));
return projections;
}
Then you had some code calling your helper method:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections());
Everything will work fine-- as long as your aliases match. The second anyone changes either of the aliases though, the query will fail.
You might be tempted to pass in an alias to a method like this:
public ProjectionList GetSharedProjections(Coffee coffeeAlias)
{
/* Same as above except with "coffeeAlias"
}
And then pass in your alias:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections(coffee));
But this won't work either. Remember that NHibernate is grabbing the name of the alias and using it directly in the generated SQL. The above code will try to use both "coffee" and "coffeeAlias" in the generated SQL and will fail.
One way to properly do this (without just hoping nobody changes alias names) is to pass around expressions and use those to reconstruct property names with the correct aliases.
You'd create a helper method that builds property access using an alias and a property:
public static PropertyProjection BuildProjection<T>(
Expression<Func<object>> aliasExpression,
Expression<Func<T, object>> propertyExpression)
{
string alias = ExpressionProcessor.FindMemberExpression(aliasExpression.Body);
string property = ExpressionProcessor.FindMemberExpression(propertyExpression.Body);
return Projections.Property(string.Format("{0}.{1}", alias, property));
}
Then, you could change the GetSharedProjections method to take an alias in the form of an expression:
public ProjectionList GetSharedProjection(Expression<Func<Coffee>> coffeeAlias)
{
TargetDTO target = null;
var projections = Projections.ProjectionList()
.Add(BuildProjection<Coffee>(coffeeAlias, c => c.CoffeeName))
.WithAlias(() => target.CoffeeName);
}
Now, calling your method would look like this:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections(() => coffee));
When someone changes your alias name you're covered. You can also safely use this method among many queries without worrying about what the name of the alias variable actually is.
Disclaimer: The following is a link to my personal blog
You can find more information about building QueryOver queries this way here.
I'm new in Linq and so I have these situation below.
Now below error during compilation, says Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Data.Entity.DbSet'.
var query = _db.Products;
if (bool) {
query = query.Where(p => p.Id == id);
}
And so I tried to change var to IQueryable and it works.
IQueryable<Product> query = _db.Products;
if (bool) {
query = query.Where(p => p.Id == id);
}
But then, I tried to change it again (see below) and it works.
var query = from product in products
select product;
if (bool) {
query = query.Where(p => p.Id == id);
}
And I just want to know why the other one works, but the other's not.
A good explanation with example might help. Thanks
The reason why the first scenario does not work is that the System.Linq.IQueryable is an interface which is implemented, among others, by the System.Data.Entity.DbSet class. In C#, if class C implements interface I, when it comes to transitions between types, you may as well treat I as C's base class (even the semantics class C : I suggest such an approach). And since you cannot implicitly (i.e. not verbosely) cast a class (or interface) to one of it's descendant classes, you get a compile-time error when trying to do it. You can do the opposite, that is implicitly cast a descendant class to it's base class (or interface). That's exactly what happens in the second scenario.
In your case, you could trick the compiler by casting explicitly:
query = (DbSet<Customer>) query.Where(p => p.Id == id);
but I would strongly advise you not to since you'll end up with a messy exception, because the result of query.Where(p => p.Id == id) is not in fact an instance of DbSet<Customer>, but rather some class representing the result of a query performed on a DbSet<Customer>, which implements the IQueryable interface.
So, to sum up, let's go through all the scenarios:
Scenario 1:
//query is of type DbSet<Customer>
var query = _db.Products;
if (bool) {
//here you're trying to assign a value of type IQueryable<Customer>
//to a variable of it's descendant type DbSet<Customer>
//hence the compile-time error
query = query.Where(p => p.Id == id);
}
Scenario 2:
//here you implicitly cast value of type DbSet<Customer>
//to IQueryable<Customer>, which is OK
IQueryable<Customer> query = _db.Products;
if (bool) {
//here you're assigning a value of type IQueryable<Customer>
//to a variable of the same type, which is also OK
query = query.Where(p => p.Id == id);
}
Scenario 3:
//I assume you have the following line in your code
var products = _db.Products;
//query is of type IQueryable<Customer>, because you perform
//a query on the DbSet<Product>
var query = from product in products
select product;
if (bool) {
//here you're assigning a value of type IQueryable<Customer>
//to a variable of the same type, which is OK
query = query.Where(p => p.Id == id);
}
EDIT
It's been a while since I answered this question, and even though the merit of it still stands, I tend to use a slightly different approach (which might have not been available at the time of original answer, I'm not sure).
The simplest (and I believe safest) way of casting an object implementing IQueryable<T> to IQueryable<T> is this:
var query = _db.Products.AsQueryable();
This simply returns the subject of the call to its IQueryable<T> interface implementation. It should not produce any overhead when executing the query. Now, there are comments suggesting to use some tricks, using which I believe might be a bad idea.
One example of such trick is to use this:
var queryable = query.Select(x => x);
While being (almost) completely benign when querying objects, it can do some harm when dealing with some implementations of IQueryable<T>. Namely, when the query is translated to, for example, a SQL query, it most likely will add a redundant "SELECT * FROM ..." to the executed query. That's the best case scenario - in the most probable scenario it will add something greatly more tedious - something like "SELECT x.P1, x.P2, ... FROM ... AS x". Of course, you might be OK with it, but you should be aware of it. Aware of the fact that, depending on implementation, calls like that might not be "free", even though appearing to do nothing.
Another example:
query.Where(x => true)
will potentially add a WHERE 1=1 to your SQL query.
When using var the compiler infers the type of the expression to the right of the assignment. When you write
var query = _db.Products;
query is of type DbSet<Product>, and it cannot be assigned any IQueryable<Product>, which the Where extension method returns.
When you used the query syntax, query was again IQueryable<Product>, which made it work. It's equivalent to writing
var query = products.Select(t => t);
The Select extension method, like Where, returns IQueryable<Product>.
It's because _db.Products isn't a query, it is a DbSet.
The second block works because you are casting it to IQueryable, and the last one works because it is an actual query.
var query = _db.Products.Where(x => true);
if (bool) {
query = query.Where(p => p.Id == id);
}
I'm building a dynamic query that can have n of Where method calls and n of SelectMany calls dependent upon user input. For example I may have:
var qZ = entityContext.TableA
.SelectMany(a=>a.TableB, (a,t)=>new{a,t} )
.Where(a=>a.t.FieldID==21)
.Where(a=> EntityFunctions.Left(a.t.Value,1)=="p")
.SelectMany(a=>a.a.TableC, (a,t)=>new{a,t} )
.Where(a=>a.t.FieldID==22)
.Where(a=> a.a.t.Value=="Peter" && a.t.Value=="Pan")
.Where(a=> a.a.a.TypeID==3)
.Select(a=> new{ a.a.a.ItemID }
).Distinct();
In the method I'm writing, I use helper methods that return an IQueryable as seen in the return line below.
return query.Provider.CreateQuery(
Expression.Call(typeof(Queryable),
"Where",
new Type[] {query.ElementType},
query.Expression, predicateLambda)
);
I'm able to create LambdaExpressions for all of the various query attribute-value pairs required, but I am unable to create one for the resultSelector of Queryable.SelectMany.
How can we create (a,t) => new{a=a, t=t} in an expression tree? Or How do we accomplish the same result as the .SelectMany above using Expression.Call like below?
Expression.Call(typeof(Queryable),
"SelectMany",
????????,
????????
);
I've tried using the SelectMany overload that doesn't require the resultSelector which works to some degree, however, I don't know how to reference the properties of t in subsequent method calls.
I've found this lambda expression ((a,t) => new{a=a, t=t}) associated with SelectMany all over the web, but I can't find any example of how to convert it to an expression tree.
UPDATE:
Let's reframe the question. I can pass the lambda like this
var q = entityContext.TableA.AsQueryable();
var q1 = Queryable.SelectMany(q, a => a.TableB, (a, t) => new { a = a, t = t });
var q2 = Queryable.Where(q1,a=>a.t.FieldID==22);
That works, however, since I don't know ahead of time how many SelectMany need to be called and since each call changes to anonymous type of the IQueriable, is there a way to cast (and re-cast) the anonymous type to a single variable? This way I can loop through and apply whatever method necessary to the variable and then enumerate to get the results once the query is built. Something like:
var q = entityContext.TableA..AsQueryable();
q = Queryable.SelectMany(q, a => a.TableB, (a, t) => new { a = a, t = t });
q = Queryable.Where(q,a=>a.t.FieldID==22);
(BTW: This doesn't work)
The way that I ended up resolving this required a paradigm shift. The first query above was based upon the fact that I learned to write queries by joining all the tables I needed together to give me access to filter on and select fields in those tables.
SelectMany() creates joins and the box around my thinking at the time required that if I need to filter on a specific column in a table, I had to join that table to my query. This in turn changed the type of my IQueryable resulting in my not being able to predict the Type of the IQueryable at design time.
Answer:
Step 1: Set the type of IQueryable to the output type it needs to return. In the case above, the result was always IQueryable.
Step 2: Utilize Expressions to dynamically create the WHERE predicate, including any and all tables necessary to create the proper filter. This always returns Expression> and all of the other variables we easily accounted for. And rememeber, in EF it isn't necessary to join table outside of Where() if they are only needed in Where().
I find LINQ a little difficult to wrap my head around. I like the concept and believe it has lots of potential. But, after writing so much SQL the syntax is just not easy for me to swallow.
A. What is the deal with multiple ways to select?
I see that I am able to create a context and perform a Select() using a method.
context.Table.Select(lamba expression);
ok...Why would I use this? How does it compare to (or does it) this type of select?
var returnVal = from o in context.Table
orderby o.Column
select o;
B. Please explain the variable nature of
**from X** in context.Table
Why do we stick a seemingly arbitrarily named variable here? Shouldn't this be a known type of type <Table>?
So...
var returnVal = context.Table.Select(o => o);
and
var returnVal = from o in context.Table
select o;
are the same. In the second case, C# just has nice syntactic sugar to give you something closer to normal SQL syntax. Notice I removed the orderby from your second query. If you wanted that in there, then the first one would become:
var returnVal = context.Table.OrderBy(o => o.Column).Select(o => o);
As for your last question... we're not sticking an arbitrarily named variable here. We're giving a name to each row so that we can reference it later on in the statement. It is implicitly typed because the system knows what type Table contains.
In response to your comment, I wanted to add one more thought. You mentioned things getting nasty with the normal method calls. It really can. Here's a simple example where its immediately much cleaner (at least, if you're used to SQL syntax) in the LINQ syntax:
var returnVal = context.Table.OrderBy(o => o.Column1)
.ThenBy(o => o.Column2)
.ThenBy(o => o.Column3)
.Select(o => o);
versus
var returnVal = from o in context.Table
orderby o.Column1, o.Column2, o.Column3
select o;
A: this is the same. The compiler transforms the query expression to method calls. Exactly the same.
B: The x is the same as in foreach(var X in context.Table). You define a name for an individual element of the table/sequence.
In B, X's type is implicit. You could just as easily do something like:
from Row x in context.Table
and it would be the same. In A, there isn't any difference between using a lambda and the equivalent full-LINQ syntax, except that you would never do .Select(x => x). It's for transforming items. Say you had a list of integers, .Select(x => x * x) would return the square of each of them.