Entity Framework Execute Expression - linq

Here is simplified code
from oi in orderItems
group oiGrouped by ...
into orderItemsGroupedBySomething
select new
{
Key = orderItemsGroupedBySomething.Key,
Revenue = /*Here is some code that I want to extract to separate method, for example*/
orderItemsGroupedBySomething.Sum(x => x.UnitPrice * x.Quantity)
}
Actually it's more complex in my case. But I think it doesn't matter. I'm not able to extract to simple method calculation of orderItemsGroupedBySomething.Sum(x => x.UnitPrice * x.Quantity) because it's not known method for EntityFramework. I tried put it to expression but I get error "The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." I compiled expression before use it in query, I think therefore I get error. How can I solve this problem?

I don't know how generic you need it to be, but something like this should work:
void Main()
{
OrderItems.GroupBy(oi => oi.SomeProp).Select(GetExpression());
}
public Expression<Func<IGrouping<KeyType, OrderItem>, dynamic>> GetExpression()
{
return (ig) => new { Key = ig.Key, Revenue = ig.Sum(x => x.UnitPrice * x.Quantity) };
}
edit: In the case of a grouping, I would probably return a Tuple in stead of an anonymous type.

I added method that return expression
public Expression<Func<OrderItem, decimal>> GetExpression()
{
return x => x.UnitPrice*x.Quantity;
}
Then I tried
from oi in orderItems
group oiGrouped by ...
into orderItemsGroupedBySomething
select new
{
Key = orderItemsGroupedBySomething.Key,
Revenue = orderItemsGroupedBySomething.Sum(GetExpression())
}
But it doesn't work such as with #LorentzVedeler answer. Because orderItemsGroupedBySomething is of type IGrouping that don't have Sum method with param of type Expression. Therefore I tried
orderItemsGroupedBySomething.AsQueryable.Sum(GetExpression())
But it causes Internal .NET Framework Data Provider error 1025. The issue was that I invoked method GetExpression() in linq. To solve this problem I put expression to local variable. The result
var expression = GetExpression();
from oi in orderItems
group oiGrouped by ...
into orderItemsGroupedBySomething
select new
{
Key = orderItemsGroupedBySomething.Key,
Revenue = orderItemsGroupedBySomething.AsQueryable.Sum(expression)
}

Related

LINQ to Entities does not recognize the method , method cannot be translated into a store expression

private void BindGrid()
{
AdvContextEF db = new AdvContextEF();
var query = from r in db.mytable
orderby r.CreateDate descending
select new
{
r.id,
r.code,
r.mytable.relatedtables[0].TheCenter.Name
};
RadGrid1.DataSource = query.ToList();
RadGrid1.DataBind();
}
I got the following error when running the code above.
LINQ to Entities does not recognize the method 'AdvContextEF.mymethod get_Item(Int32)' method, and this method cannot be translated into a store expression.
thank you
Instead of trying to index into r.mytable.relatedtables[0], try using .FirstOrDefault().
r.mytable.relatedtables.FirstOrDefault().TheCenter.Name
or
Name = r.mytable.relatedtables.Select(rt => rt.TheCenter.Name).FirstOrDefault()

String extension method in Linq query

How to use string extension method in linq query:
public NewsType GetNewsType(string name)
{
var newsType = db.NewsTypes.FirstOrDefault(x => x.Name.ToFriendlyUrl() ==
name.ToFriendlyUrl());
return newsType;
}
Above query x.Name.ToFriendlyUrl() is not allowed at the minute. Is anyone know how to achieve with it.
Extension methods are indeed allowed in LINQ queries, moreover the LINQ methods themselves are implemented as extension methods.
It's quite another issue however, to use extension methods (or most other methods) in LINQ-to-SQL or LINQ-to-Entities queries. Those queries are not actually run in the C# code, but they are treated like expressions that are translated to SQL. I.e.
db.News.Where(x => x.Published).Select(x => x.Name)
is translated to the SQL Statement
Select Name
From News
Where Published = 1
and it's results are returned to the C# code.
Since there is not way to transfer the ToFriendlyUrl() method to SQL, your code throws an error.
You have basically, two solutions/workarounds. One is to transform the call to a form could be translated into SQL, e.g. if the ToFriendlyUrl() method was just:
public static string ToFriendlyURL(this string value)
{
return value.ToLower();
}
you can inline that code in the LINQ call, and that would work. If however, the methods is more complex, than your only solution is to just fetch the data from the base and then process it on the C# side:
var newsTypeQuery = db.NewsTypes.Where(x => // other conditions, if any);
var newsTypes = newsTypes.ToList(); //forces execution of the query
// the result is now a C# list
var newsType = newsTypes.FirstOrDefault(x =>
x.Name.ToFriendlyUrl() == name.ToFriendlyUrl());
Assuming the NewsTypes is an IQueryable this is a result of Entity Framework not being able to convert you extension method into SQL (how should it?). Unless you can rewrite your predicate into something that Entity Framework can translate into SQL you will have to perform the query client side:
public NewsType GetNewsType(string name)
{
var newsType = db.NewsTypes.AsEnumerable().FirstOrDefault(x => x.Name.ToFriendlyUrl() == name.ToFriendlyUrl());
return newsType;
}
Notice how AsEnumerable() has been added before FirstOrDefault. Unfortunately this may pull all the rows returned by NewsTypes from the server to client and thus may be quite costly.
This
var newsType = db.NewsTypes.FirstOrDefault(
x => x.Name.ToFriendlyUrl() == name.ToFriendlyUrl());
can't be done in Entity Framework. ToFriendlyUrl is an extension method. It's something that is in the "client" computer. The query will be executed on the SQL server. The SQL server doesn't have a ToFriendlyUrl function.
The "standard" solution is to save in a second column named FriendlyName a precalculated version of the ToFriendlyUrl(), so your query becomes:
var friendlyName = name.ToFriendlyUrl();
var newsType = db.NewsTypes.FirstOrDefault(
x => x.FriendlyName == friendlyName);
Instead try like this
public NewsType GetNewsType(string name)
{
var newsType = db.NewsTypes.FirstOrDefault(x => x.Name == name).ToFriendlyUrl();
return newsType;
}

LINQ to Entities does not recognize the method 'Boolean CheckMeetingSettings(Int64, Int64)' method

I am working with code first approach in EDM and facing an error for which I can't the solution.Pls help me
LINQ to Entities does not recognize the method 'Boolean
CheckMeetingSettings(Int64, Int64)' method, and this method cannot be
translated into a store expression.
My code is following(this is the query which I have written
from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
}
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
Please help me out of this.
EF can not convert custom code to SQL. Try iterating the result set and assigning the property outside the LINQ query.
var people = (from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
order by /**/
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
}).Skip(/*records count to skip*/)
.Take(/*records count to retrieve*/)
.ToList();
people.ForEach(p => p.CanSendMeetingRequest = CheckMeetingSettings(6327, p.Id));
With Entity Framework, you cannot mix code that runs on the database server with code that runs inside the application. The only way you could write a query like this, is if you defined a function inside SQL Server to implement the code that you've written.
More information on how to expose that function to LINQ to Entities can be found here.
Alternatively, you would have to call CheckMeetingSettings outside the initial query, as Eranga demonstrated.
Try:
var personDetails = obj.tempPersonConferenceDbSet.Where(p=>p.ConferenceId == 2).AsEnumerable().Select(p=> new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
});
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
You must use AsEnumerable() so you can preform CheckMeetingSettings.
Linq to Entities can't translate your custom code into a SQL query.
You might consider first selecting only the database columns, then add a .ToList() to force the query to resolve. After you have those results you van do another select where you add the information from your CheckMeetingSettings method.
I'm more comfortable with the fluid syntax so I've used that in the following example.
var query = obj.tempPersonConferenceDbSet
.Where(per => per.Conference.Id == 2).Select(per => new { Id = per.Person.Id, JobTitle = per.Person.JobTitle })
.ToList()
.Select(per => new PersonDetails { Id = per.Id,
JobTitle = per.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327, per.Person.Id) })
If your CheckMeetingSettings method also accesses the database you might want to consider not using a seperate method to prevent a SELECT N+1 scenario and try to express the logic as part of the query in terms that the database can understand.

Nhibernate 3.0 LINQ: Problem returning to IQueryable (non generic version) - doesn't allow ToList()

I am using the latest Nhibernate and i have a linq query to return just 1 column. so I can't use for example IQueryable as there is no entity class - i am returning only 1 column. But return to IQueryable Non Generic version doesn't provide the ToList method
Here is the method
public IQueryable GetCode()
{
using (ITransaction transaction = _session.BeginTransaction())
{
var results = (from c in _session.Query<Client>()
select new
{
Group = c.Code
}).Distinct();
}
}
Of course if i do this (see below) i get the ToList method on my IQueryable
public IQueryable<Client> GetCode()
{
using (ITransaction transaction = _session.BeginTransaction())
{
var results = (from c in _session.Query<Client>()
select c;
}
}
The problem being is that i need to do DISTINCT and use only 1 column.
Any ideas, i am at a loss
Thanks in advance
EDIT
When i look at the type that is returned via IQueryable it is
{NHibernate.Linq.NhQueryable<<>f__AnonymousType6>}
and looking under the base class of what is returned i see an exception
Expression type 10005 is not supported by this SelectClauseVisitor.
Wouldn't the following work?
public IQueryable<X> GetCode() // X = the type of Client.Code
{
using (ITransaction transaction = _session.BeginTransaction())
{
var results = (from c in _session.Query<Client>()
select c.Code).Distinct();
}
}
The problem here is not just that you can't call ToList on a non-generic IQueryable, but that the entire result is untyped, so you cannot read the Code property of each element either. (This can be worked around with C# 4's dynamic type, but that's not really what you want here.)
In your case, I don't see why you really need to construct an anonymous type just to return a distinct sequence of Code values renamed as Group. Returning the field's value should be sufficient.
If you'd need to return more than just one column, you should create an explicit type, rather than using an anonymous type, so you can say
public IQueryable<ClientGroupAndSomething> GetCode()
{
using (ITransaction transaction = _session.BeginTransaction())
{
var results = (from c in _session.Query<Client>()
select new ClientGroupAndSomething
{
Group = c.Code,
...
}).Distinct();
}
}

linq help - newbie

how come this work
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == 1
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
but this does not
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == postId
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
The issue is most likely in the implementation of the query provider.
pcm.PostId == 1
and
pcm.PostId == postId
actually have a big difference. In the expression tree the first is generated as a ConstantExpression which doesnt need to be evaulated.
With the second, the compiler actually generates an inner class here (this is the _DisplayClassX that you see). This class will have a property (will most likely be the same name as your parameter) and the expression tree will create a MemberAccessExpression which points to the auto-generated DisplayClassX. When you query provider comes accross this you need to Compile() the Lambda expression and evaluate the delegate to get the value to use in your query.
Hope this helps.
cosullivan
The problem is not the linq itself,
you need to be sure that the context or provider object is able to fetch the data.
try testing the
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
objects and see if they are populated or if they behaving as required.
you may want to search the generated code for c__DisplayClass1 and see what you can see there. some times the generated code dose some weird things.
when you step into you code check the locals and the variable values. this may also give you some clues.
Edit : Have you tried to return a List<> collection ? or an Enumerable type?
Edit : What is the real type of the item and query may not be iterable

Resources