I have this method in a class called Invoice:
public static Expression<Func<Invoice, bool>> IsAllocated()
{
return i => i.TotalAmountDue == i.GetAllocationsTotal();
}
I have a list like this:
IQueryable<Invoice> invoices
And I need to filter it like that (it's Linq to Entity):
var filteredInvoices = invoices.Where(i => Invoice.IsAllocated());
In this line I'm getting two errors:
Cannot resolve method ... candidates are .... one in Enumerable and the other on in Queryable.
And also:
Cannot convert expression type Expression<Func<Invoice,bool>> to
return type 'bool'
I've tried a lot of things I've found in SO with no luck. Can someone say me what is missing here or at least, which one of the two errors is at the root of the problem?
Your method returns an appropriate expression tree already - you just need to call it, not call it in a lambda expression:
var filteredInvoices = invoices.Where(Invoice.IsAllocated());
Expression are representation and not delegate by themselves. You should create a delegate out of it first
static Expression<Func<Invoice, bool>> IsAllocatedExpr()
{
return i => i.TotalAmountDue == i.GetAllocationsTotal();
}
public static Func<Invoice, bool> IsAllocated = IsAllocatedExpr().Compile();
and then
var filteredInvoices = invoices.Where(i => Invoice.IsAllocated(i));
Related
I need some help with a LINQ extension that I'm tying to write. I'm trying to create an extension that calculates the row index of a given Id within an IQueryable - Except that type can be any table. I think I've got most of the way there but I just can't seem to complete it. I'm getting the following error message on the line
Select(lambda)
The type arguments for method
'System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable,
System.Func)' cannot be inferred from the usage.
Try specifying the type arguments
explicitly. c:\users\shawn_000\documents\visual studio
2013\projects\dexconstruktaweb\dexconstruktaweb\generalhelper.cs 157 17 DexConstruktaWeb
private class GetRowCountClass
{
public GetRowCountClass(int id, int index)
{
this.Id = id;
this.Index = index;
}
public int Id { get; set; }
public int Index { get; set; }
}
public static int GetRowCount<T>(this IQueryable<T> query, int id)
{
Type sourceType = typeof(T);
ParameterExpression[] parameter = new ParameterExpression[2];
parameter[0] = Expression.Parameter(sourceType, "x");
parameter[1] = Expression.Parameter(typeof(int), "index");
Type getRowCountType = typeof(GetRowCountClass);
ConstructorInfo constructor = getRowCountType.GetConstructor(new[] { typeof(int), typeof(int)} );
PropertyInfo pi = sourceType.GetProperty("Id");
Expression expr = Expression.Property(parameter[0], pi);
NewExpression member = LambdaExpression.New(constructor,new Expression[] { expr, parameter[1]});
LambdaExpression lambda = Expression.Lambda(member, parameter);
var item = query.AsEnumerable()
.Select(lambda);
}
I know that after the select I need the following line to get the index to return, but for now I'm stumped. Any help would be appreciated. Thanks.
.SingleOrDefault(x => x.Id == id).index;
Update
I've done some further digging and found that some LINQ statements do not work for LINQ to Entities, which is what I'm using:
http://msdn.microsoft.com/en-us/library/bb738550.aspx
http://msdn.microsoft.com/en-us/library/bb896317.aspx
In particular "Most overloads of the projection and filtering methods are supported in LINQ to Entities, with the exception of those that accept a positional argument."
To get around this I was using a call to AsEnumerable() to turn this into a generic Enumerable, then the call to Select and SingleOrDefault as described above. However, I have found that there is no difference in the SQL created between a call to AsEnumerable and ToList, so I have decided to simply call:
.ToList().FindIndex(e => e.Id == id)
directly on my IQueryable without creating an Extension as it is a small enough piece of code.
Thanks for all your help. If someone still sees a better way to do this please let me know.
cheers,
Update 2
As a bit of a learning exercise I took Servy's suggestion and this answer Creating Dynamic Predicates- passing in property to a function as parameter and came up with the following:
public static int GetRowIndex<T>(this IQueryable<T> query, Expression<Func<T, int>> property, int id)
{
var lambda = Expression.Lambda<Predicate<T>>(
Expression.Equal(property.Body, Expression.Constant(id)), property.Parameters);
return query.ToList().FindIndex(lambda.Compile());
}
This can be called like:
var result2 = query.GetRowIndex(x => x.Id, id);
Where query is of Type IQueryable.
There is very little point to it though and it is only really useful as a learning exercise.
Thanks.
Your lambda always returns GetRowCountClass and takes T so you can use generic version of Expression.Lambda method:
var lambda = Expression.Lambda<Func<T, GetRowCountClass>>(member, parameter);
var item = query.Select(lambda);
return item.SingleOrDefault(x => x.Id == id).Index;
This code correctly returns one row:
_loadedAssemblies.ForEach(x =>
{
foundTypes.AddRange(from t in x.GetTypes()
where t.GetInterfaces().Contains(typeof(TInterface))
&& t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`')
select t);
}
However, when I use PredicateBuilder, I get zero rows:
var compiledPredicate = CompiledPredicate<TInterface>();
_loadedAssemblies.ForEach(x =>
{
foundTypes.AddRange(from t in x.GetTypes()
where compiledPredicate.Invoke(typeof(TInterface))
select t);
}
private static Func<Type, bool> CompiledPredicate<T>() where T : class
{
// True means all records will be returned if no other predicates are applied.
var predicate = PredicateBuilder.True<Type>();
// Get types that implement the interface (T).
predicate = predicate.And(t => t.GetInterfaces().Contains(typeof(T)));
// If the config file includes filtering by base class, then filter by it.
if (!string.IsNullOrWhiteSpace(_baseClass))
{
Type baseClass = Type.GetType(_baseClass);
predicate = predicate.And(t => t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`'));
}
return predicate.Compile();
}
Someone suggested creating a copy of my loop variable, but I tried that and I still get zero rows. I'm not sure why using PredicateBuilder returns no rows. Any idea what I'm missing?
The change that you mentioned in comments (foundTypes.AddRange(x.GetTypes().AsQueryable().Where(compiledPredicate));) had nothing at all to do with the fact that you were using AsQueryable. In the first case you're passing in a hard coded type to each call of your predicate, in the second you're passing the given item from the sequence. Had you removed the AsQueryable and used Enumerable.Where it would also work, or had you passed the current item, rather than a hard coded type, when invoking it that would also work.
So you can simply do:
foundTypes.AddRange(x.GetTypes().Where(compiledPredicate));
Also, when creating the predicate, there's no need to do as much work as you're doing. Expressions take a fair amount of extra work to deal with. With linq to objects you only need to deal with delegates, which are much less finicky.
private static Func<Type, bool> CompiledPredicate<T>() where T : class
{
Func<Type, bool> predicate = t => t.GetInterfaces().Contains(typeof(T));
if (!string.IsNullOrWhiteSpace(_baseClass))
{
Type baseClass = Type.GetType(_baseClass);
return t => predicate(t) &&
t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`');
}
return predicate;
}
I am using the Albaharis PredicateBuilder as found here http://www.albahari.com/nutshell/predicatebuilder.aspx to filter results in a Linq-to-SQL application. This has been working great.
What I am trying to do now, is reuse the existing filtering predicate expression to filter an object that has the existing filtered object as a property.
For example, I have 2 classes, Order and Customer. I already have a method that returns a Expression<Func<Customer, bool>>, which is built using the above mentioned predicate builder. I now want to reuse this in my Order filtering method, which will return a Expression<Func<Customer, bool>> by somehow passing the Order.Customer property (expression?) into my Customer filter method.
I have something like this (far from complete, but I hope you get the idea):
public class CustomerSearchCriteria
{
public Expression<Func<Customer, bool>> FilterPredicate()
{
// Start with predicate to include everything
var result = PredicateBuilder.True<Customer>();
// Build predicate from criteria
if (!String.IsNullOrEmpty(this.Name))
{
result = result.And(c => SqlMethods.Like(c.Name, this.Name));
}
// etc. etc. etc
}
public class OrderSearchCriteria
{
public Expression<Func<Order, bool>> FilterPredicate()
{
// Start with predicate to include everything
var result = PredicateBuilder.True<Order>();
// Build predicate from criteria
if (!String.IsNullOrEmpty(this.Reference))
{
result = result.And(o => SqlMethods.Like(o.Reference, this.Reference));
}
// etc. etc. etc
// This is where I would like to do something like:
// result = result.And(o => o.Customer "matches" this.CustomerCriteria.FilterPredicate()
}
Can any Linq expression guru help me?
Thanks in advance.
If you use the Albaharis' LinqKit, you should be able to do something like this:
var customerFilter = this.CustomerCriteria.FilterPredicate();
// create an expression that shows us invoking the filter on o.Customer
Expression<Func<Order, bool>> customerOrderFilter =
o => customerFilter.Invoke(o.Customer);
// "Expand" the expression: this creates a new expression tree
// where the "Invoke" is replaced by the actual predicate.
result = result.And(customerOrderFilter.Expand())
I am using an interface I found, which has a method that takes a LINQ expression as a parameter.
How would I implement this method to use the LINQ Expression? I can see it being very useful, but dont how to write the code to use it!!
Its a repository interface.
signature is...
IQueryable<T> Get(Expression<Func<T, bool>> criteria);
Sounds like you are looking for something like this:
List<T> myList = new List<T>();
...
public IQueryable<int> Get(Expression<Func<int, bool>> criteria)
{
return myList.Where(criteria.Compile()).AsQueryable();
}
This passes your expression criteria to the linq-method Where. You can then call it like this:
foreach(var something in myClass.Get(o => o.someProperty == 10))
{
...
}
Of course, this is pretty stupid; it would be better to just implement IEnumerable<T>...
IQueryable<T> has an .Where() overload that takes an Expression<Func<T>> parameter. When assuming that this is a Linq2Sql or Linq2Entities repository, something like this should work
class MyRepository
{
ObjectContext context = // initialize somehow;
public IQueryable<int> Get(Expression<Func<int, bool>> predicate)
{
return context.SomeObject.Where(predicate);
}
}
If that's not the case, and you only have an enumerable, you can use AsQuerably() as the first step in the chain to convert it to IQuerably, giving you the option to use the expression based predicate:
public IQueryable<int> Get(Expression<Func<int, bool>> predicate)
{
return mySimpleList.AsQuerable().Where(predicate);
}
That is a predicate expression; something that indicates data to include.
So, to get a single record you could use:
int rowId = 123;
var row = foo.Get(x => x.Id == rowId).Single();
Or to get all data matching some condition you could use:
var allDeleted = foo.Get(x => x.IsDeleted).ToList();
Note that this should be composable, for more fun:
var today = from row in foo.Get(x => x.DateCreated > DateTime.Today)
orderby row.Name
select new {row.Id, row.Name};
So, I am using the Linq entity framework. I have 2 entities: Content and Tag. They are in a many-to-many relationship with one another. Content can have many Tags and Tag can have many Contents. So I am trying to write a query to select all contents where any tags names are equal to blah
The entities both have a collection of the other entity as a property(but no IDs). This is where I am struggling. I do have a custom expression for Contains (so, whoever may help me, you can assume that I can do a "contains" for a collection). I got this expression from: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2670710&SiteID=1
Edit 1
I ended up finding my own answer.
After reading about the PredicateBuilder, reading all of the wonderful posts that people sent to me, posting on other sites, and then reading more on Combining Predicates and Canonical Function Mapping.. oh and I picked up a bit from Calling functions in LINQ queries (some of these classes were taken from these pages).
I FINALLY have a solution!!! Though there is a piece that is a bit hacked...
Let's get the hacked piece over with :(
I had to use reflector and copy the ExpressionVisitor class that is marked as internal. I then had to make some minor changes to it, to get it to work. I had to create two exceptions (because it was newing internal exceptions. I also had to change the ReadOnlyCollection() method's return from:
return sequence.ToReadOnlyCollection<Expression>();
To:
return sequence.AsReadOnly();
I would post the class, but it is quite large and I don't want to clutter this post any more than it's already going to be. I hope that in the future that class can be removed from my library and that Microsoft will make it public. Moving on...
I added a ParameterRebinder class:
public class ParameterRebinder : ExpressionVisitor {
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) {
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) {
return new ParameterRebinder(map).Visit(exp);
}
internal override Expression VisitParameter(ParameterExpression p) {
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement)) {
p = replacement;
}
return base.VisitParameter(p);
}
}
Then I added a ExpressionExtensions class:
public static class ExpressionExtensions {
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) {
// build parameter map (from parameters of second to parameters of first)
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {
return first.Compose(second, Expression.And);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {
return first.Compose(second, Expression.Or);
}
}
And the last class I added was PredicateBuilder:
public static class PredicateBuilder {
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
}
This is my result... I was able to execute this code and get back the resulting "content" entities that have matching "tag" entities from the tags that I was searching for!
public static IList<Content> GetAllContentByTags(IList<Tag> tags) {
IQueryable<Content> contentQuery = ...
Expression<Func<Content, bool>> predicate = PredicateBuilder.False<Content>();
foreach (Tag individualTag in tags) {
Tag tagParameter = individualTag;
predicate = predicate.Or(p => p.Tags.Any(tag => tag.Name.Equals(tagParameter.Name)));
}
IQueryable<Content> resultExpressions = contentQuery.Where(predicate);
return resultExpressions.ToList();
}
Please let me know if anyone needs help with this same thing, if you would like me to send you files for this, or just need more info.
Summing it up...
contentQuery.Where(
content => content.Tags.Any(tag => tags.Any(t => t.Name == tag.Name))
);
So is that what you're expecting?
I'm a little confused.
This is what the question itself asks for:
contentQuery.Where(
content => content.Tags.Any(tag => tag.Name == "blah")
);
I'm not sure what the thought process was to get to the questioner's code, really, and I'm not entirely sure exactly what its really doing. The one thing I'm really sure of is that .AsQueryable() call is completely unnecessary -- either .Tags is already an IQueryable, or the .AsQueryable() is just going to fake it for you -- adding extra calls in where there doesn't need to be any.
The error is related to the 'tags' variable. LINQ to Entities does not support a parameter that is a collection of values. Simply calling tags.AsQueryable() -- as suggested in an ealier answer -- will not work either because the default in-memory LINQ query provider is not compatible with LINQ to Entities (or other relational providers).
As a workaround, you can manually build up the filter using the expression API (see this forum post) and apply it as follows:
var filter = BuildContainsExpression<Element, string>(e => e.Name, tags.Select(t => t.Name));
var query = source.Where(e => e.NestedValues.Any(filter));
tags.Select(testTag => testTag.Name)
Where does the tags variable gets initialized from? What is it?
NOTE: please edit the question itself, rather than replying with an answer -- this is not a discussion thread, and they can re-order themselves at any time
If you're searching for all Contents that are marked with any one of a set of tags:
IEnumerable<Tag> otherTags;
...
var query = from content in contentQuery
where content.Tags.Intersection(otherTags).Any()
select content;
It looks like you might be using LINQ To SQL, in which case it might be better if you write a stored procedure to do this one: using LINQ to do this will probably not run on SQL Server -- it's very likely it will try to pull down everything from contentQuery and fetch all the .Tags collections. I'd have to actually set up a server to check that, though.