Error while re-using an expression using PredicateBuilder in LINQ - c#

I am trying to re-use an expression in a LINQ query but I get an exception saying "Code supposed to be unreachable". I'm not very much versed with PredicateBuilder. So pardon me if I look stupid somewhere. Below are the code snippets.
The expression that I am building via PredicateBuilder for re-use:
private static Expression <Func <DiscussionTopic , bool >> TopicExpr(Guid topicId, TaskMember taskMember, bool invert = false)
{
var predicate = PredicateBuilder.True<DiscussionTopic >();
predicate = predicate.And(topic => topic.TopicType == TopicType.Topic && topic.DiscussionTopicId == topicId);
predicate = predicate.And(ExpressionStore.IsTopicAnsweredExpression(taskMember.PersonId));
predicate = predicate.And(topic => (topic.TopicGroup == null || topic.TopicGroup.TopicVisibility == TopicVisibilityType .AllParticipants ||
(topic.TopicGroup.TopicVisibilityTags.Any(tv => taskMember.Person.PeopleTags.Any(pt => pt.ContentTagId == tv.ContentTagId) || taskMember.TaskMemberTags.Any(tmt => tmt.ContentTagId == tv.ContentTagId)))));
predicate = predicate.And(topic => (topic.TopicVisibility == TopicVisibilityType.AllParticipants ||
(topic.TopicVisibilityTags.Any(tv => taskMember.Person.PeopleTags.Any(pt => pt.ContentTagId == tv.ContentTagId) || taskMember.TaskMemberTags.Any(tmt => tmt.ContentTagId == tv.ContentTagId)))));
return predicate;
}
Next, I am trying to use the above expression in a nested query as below:
public static IQueryable <TaskMember > ApplyTopicsCompletedFilter(this IQueryable<TaskMember > input, Guid[] topicIds, bool invert = false)
{
var predicate = PredicateBuilder.True<TaskMember >();
predicate = predicate.And(taskMember => taskMember.TaskMembership.Discussions.Any(discussion => topicIds.All(topicId =>
discussion.DiscussionTopics.AsQueryable().Any(TopicExpr(topicId, taskMember, invert)))));
input = input.Where(predicate);
return input;
}
Some points to mention which are skipped for brevity:
The ApplyTopicsCompletedFilter function is an extension method that receives an already constructed query as input by the caller. Therefore, AsExpandable() operator is applied in the caller and not here.
ExpressionStore.IsTopicAnsweredExpression in line 5 in TopicExpr is an external query that has a complex logic for checking if a member has answered a topic in a discussion. I have skipped the definition here but it's a normal expression with signature Expression<Func<DiscussionTopic, bool> returned by a function that takes a PersonId as a parameter.
If I remove AsQueryable() from line 4 in ApplyTopicsCompletedFilter function, I receive internal data error. Of course if I do that, I also have to do TopicExpr(....).Compile() in the same line otherwise the code won't compile.
Please help as I have wasted almost a day trying to find a nice way of sharing business logic across different functions in our application. Our code is quite complex and uses a lot of sub-queries as well. That's why I am looking for a way where I can share a piece of logic no matter if it appears in a parent query or a sub-query inside a parent query.
Edit:
I just commented everything inside TopicExpr and now it just looks like this:
private static Expression<Func<DiscussionTopic, bool>> TopicExpr(Guid topicId, TaskMember taskMember, bool invert = false)
{
var predicate = PredicateBuilder.True<DiscussionTopic>();
predicate = predicate.And(topic => topic.TopicType == TopicType.Topic && topic.DiscussionTopicId == topicId);
return predicate;
}
I have done this to make the query simple to test. Here is the complete flow now:
[Route("api/accounts/testPredicate")]
[HttpGet]
public IQueryable<apiPerson> TestPredicate()
{
return this.TestPredicate(this.CurrentAccountId, new[] { MembershipStatusType.Member }, new apiFilterData { TopicsCompleted = new[] { Guid.Parse("<some guid>") } }).Select(tm => tm.Person).ToApiObjects();
}
public IQueryable<TaskMember> TestPredicate(Guid currentAccountId, MembershipStatusType[] statusTypes = null, apiFilterData filterData = null)
{
var query = this.Db.Set<TaskMember>().Where(t => t.Person.AccountId == currentAccountId).AsExpandable();
if (statusTypes != null)
query = query.Where(t => statusTypes.Contains(t.Status));
if (filterData.TopicsCompleted != null && filterData.TopicsCompleted.Length > 0)
query = query.ApplyTopicsCompletedFilterWithPredicate(filterData.TopicsCompleted);
if (filterData.TopicsNotCompleted != null && filterData.TopicsNotCompleted.Length > 0)
query = query.ApplyTopicsCompletedFilterWithPredicate(filterData.TopicsNotCompleted, true);
return query;
}
private static Expression<Func<DiscussionTopic, bool>> TopicExpr(Guid topicId, TaskMember taskMember, bool invert = false)
{
var predicate = PredicateBuilder.True<DiscussionTopic>();
predicate = predicate.And(topic => topic.TopicType == TopicType.Topic && topic.DiscussionTopicId == topicId);
return predicate;
}
public static IQueryable<TaskMember> ApplyTopicsCompletedFilterWithPredicate(this IQueryable<TaskMember> input, Guid[] topicIds, bool invert = false)
{
var predicate = PredicateBuilder.True<TaskMember>();
predicate = predicate.And(taskMember => taskMember.TaskMembership.Discussions.AsQueryable().Any(discussion => topicIds.All(topicId =>
discussion.DiscussionTopics.AsQueryable().Any(TopicExpr(topicId, taskMember, invert)))));
input = input.Where(predicate);
return input;
}
public static IQueryable<apiTopicSimple> ToApiObjects(this IQueryable<DiscussionTopic> items, Guid currentUserId, MembershipStatusType membershipStatus, bool stagingSite)
{
return from t in items
let ms = membershipStatus
let uId = currentUserId
let sS = stagingSite
select new apiTopicSimple
{
//Property initialization
};
}
PS: These functions are in different files inside the project but I have put them here at one place for definition purposes so that someone can go through the complete flow.

Related

Multiple conditional where on list c#

I need to add multiple conditional where on list but i can't
List<Account> accounts = getAccount();
and after on my liste i need to apply multiple condition like this how can i do it please beacause i can't make And on prdicate. This is my code
Func<Account, bool> predicate = X => true;
if (request.id!= 0)
{
predicate = predicate.And(giftCard => giftCard.Id == request.Id);
}
if (request.code> 0)
{
predicate = predicate.And(giftCard => giftCard.code== request.code);
}
if (request.cjn> 0)
{
predicate = predicate.And(giftCard => giftCard.cjn== request.cjn);
}
var resuly=accounts.where(predicate);
You could use linqKit for this scenario.
It has that exact And() function you used in your sample code.

Modifying Linq to remove repetitiveness

private readonly IRepository<Order> _orderRepo; // initialized in the constructor
IRepository<Order> GetOrder(string orderstate)
{
if(orderstate == null)
{
return null;
}
IQueryable<Order> query = null;
if(orderstate == "OrderStateChanged")
{
query = (from c in _orderRepo.Table
where c.OrderStateChanged != 0
select c
);
}
else if (orderstate == "PaymentStateChanged")
{
query = (from c in _orderRepo.Table
where c.PaymentStateChanged != 0
select c
);
}
/*More else if statement*/
}
I used LINQ to extract data from the repo and I have more else if statement. I want to remove the repetitive behavior of my code.
I have a clue "Expression Tree" but I can't understand How can I use that in my code Or suggest me any other way to remove
repetitiveness.
If you really want to prevent manually mapping orderState to members (using if/else, switch, IDictionary, ...), your only option are indeed expression trees:
var orderType = typeof(Order);
var param = Expression.Parameter(orderType);
var member = orderType.GetMember(orderState).FirstOrDefault();
if (member == null)
{
/* requested member of "Order" does not exist */
}
var filter = Expression.Lambda<Func<Order, bool>>( // "param => param.member != 0"
Expression.NotEqual( // "param.member != 0"
Expression.MakeMemberAccess(param, member), // "param.member"
Expression.Constant(0)), // "0"
param); // "param =>"
query = _orderRepo.Table.Where(filter);
Alternative (simpler, but throws ArgumentException if the member doesn't exist)
var orderType = typeof(Order);
var param = Expression.Parameter(orderType);
var member = Expression.PropertyOrField(param, orderState); // may throw ArgumentException!
var filter = Expression.Lambda<Func<Order, bool>>(
Expression.NotEqual(member, Expression.Constant(0)),
param);
query = _orderRepo.Table.Where(filter);
This way you are really generic, even if the object layout of Order changes. One disadvantage is of course the risk of invalid orderState values leading to non-existing members of Order but I'm sure you had some kind of mechanism already, anyway.
Further reading
MSDN - Expression Trees
MSDN - How to: Use Expression Trees to Build Dynamic Queries
CodeProject - Expression Tree Basics
You won't get it much better, but the extension method syntax is (IMHO) a bit more concise for this sort of code
IEnumerable<Order> GetOrder(string orderstate)
{
if(orderstate == null)
{
return null;
}
IQueryable<Order> query = _orderRep.Table;
if(orderstate == "OrderStateChanged")
{
query = query.Where(c => c.OrderStateChanged != 0);
}
else if (orderstate == "PaymentStateChanged")
{
query = query.Where(c => c.PaymentStateChanged != 0);
}
/*More else if statement*/
}
If you need this filtering in multiple places, you could maintain some kind of dictionary with the expression predicates:
static IDictionary<string, Expression<Func<Order,bool>> Predicates = new Dictionary<string, Expression<Func<Order,bool>>
{
{"OrderStateChanged", o => o.OrderStateChanged != 0},
{"OrderPaymentChanged", o => o.PaymentStateChanged != 0},
};
Then your method could become something like:
IEnumerable<Order> GetOrder(string orderstate)
{
if (orderstate == null || !Predicates.ContainsKey(orderstate))
return null; // or throw exception
var predicate = Predicates[orderstate];
return _orderRep.Table.Where(predicate);
}
LINQ is composable by nature. This means that you can do this:
var query = _orderRepoTable.AsQueryable();
switch (orderState)
{
case "OrderStateChanged": query = query.Where(c => c.OrderStateChanged != 0); break;
...
}
// Now query has the filters you want.
I'd still stick with the explicit filters, rather than using expression trees to build them based on orderState directly - that's just asking for trouble. Using an enum for orderState might also be a good idea. Don't worry, this isn't really code repetition - it's just a definition of a language, basically.

Creating a composite condition using anonymous filter method

I am trying to edit a search tool using linq,
What I like a filter in where clause is (ItemNumber == X AND ( StatementStatus == SatusA Or StatementStatus == StatusB ) )
But right now, it is like:
What I like a filter in where clause is (ItemNumber == X AND StatementStatus == SatusA Or StatementStatus == StatusB )
as AND has higher operational priority over OR the result is not what I want. :)
Could you please help?
using (var ctx = new MyContext()) {
Func<Statement, bool> filter = null;
if (!string.IsNullOrEmpty(request.ItemNumber))
filter = new Func<Statement, bool>(s => s.StatementDetails.Any(sd => sd.ItemNumber == request.ItemNumber));
if (request.StatusA)
filter = filter == null ? new Func<Statement, bool>(s => s.StatementStatus == StatementStatusType.StatusA) :
filter.And(s => s.StatementStatus == StatementStatusType.StatusA);
if (request.StatusB)
filter = filter == null ? new Func<Statement, bool>(s => s.StatementStatus == StatementStatusType.StatusB) :
filter.Or(s => s.StatementStatus == StatementStatusType.StatusB);
var results = ctx.Statements
.Include("StatementDetails")
.Include("StatementDetails.Entry")
.Where(filter)
.Take(100)
.Select(s => new StatementSearchResultDTO{ ....
}
}
That's happens not because AND have higher priority than OR. What happens in reality:
var firstFilter = ...; // itemNumber
var secondFilter = ...; // statusA
var firstAndSecondFilter = firstFilter.And(secondFilter); // itemNumber && statusA
var thirdFilter = ...; // statusB
var endFilter = firstAndSecondFilter.Or(thirdFilter) // (itemNumber && statusA) || statusB.
The problem - wrong control flow. You must to do something like that:
var filterByA = ...;
var filterByB = ...;
var filterByAorB = filterByA.Or(filterByB);
var filterByNumber = ...;
var endFiler = filterByNumber.And(filterByAorB);
And your code is bad, not just because it works wrong, but because it's hard to write code in such style. Reasons:
This code doesn't follow DRY principle. You have two same lambdas that checks for StatusA (look in your ternary operator) and two same lambdas that checks for StatusB
You have too long ternary operator with null checks. That's bad because you don't see general picture, your eyes focused on syntax problems. You may write and extension method AndNullable for funcs. Like this:
static Func<T1, TOut> AndNullable<T1, TOut>(this Func<T1, TOut> firstFunc, Func<T1, TOut> secondFunc) {
if (firstFunc != null) {
if (secondFunc != null)
return firstFunc.And(secondFunc);
else
return firstFunc;
}
else {
if (secondFunc != null)
return secondFunc;
else
return null;
}
}
And that same for Or. Now your code can be wroted like this:
Func<Statement, bool> filter = null;
if (request.StatusA)
filter = s => s.StatementStatus == StatementStatusType.StatusA;
if (request.StatusB)
filter = filter.OrNullable(s => s.StatementStatus == StatementStatusType.StatusB);
if (!string.IsNullOrEmpty(request.ItemNumber))
filter = filter.AndNullable(s => s.StatementDetails.Any(sd => sd.ItemNumber == request.ItemNumber));
Reads more better.
Your filter is global filter. Writing of global filter is simpler for few filter conditions and number of lines is small, but it's more complicated to understand your filter. Rewrite it in this way:
Func<Statement, bool> filterByStatusA = null;
Func<Statement, bool> filterByStatusB = null;
if (request.StatusA)
filterByStatusA = s => s.StatementStatus == StatementStatusType.StatusA;
if (request.StatusB)
filterByStatusB = s => s.StatementStatus == StatementStatusType.StatusB;
Func<Statement, bool> filterByStatuses = filterByStatusA.OrNullable(filterByStatusB);
Func<Statement, bool> filterByItemNumber = null;
if (!string.IsNullOrEmpty(request.ItemNumber))
filterByItemNumber = s => s.StatementDetails.Any(sd => sd.ItemNumber == request.ItemNumber);
Func<Statement, bool> endFilter = filterByItemNumber.And(filterByStatuses);
Okay, we have outthinked how we can write filters by combining them as Func<..> but we still have problems.
What problems we will got, if result filter is null? Answer: ArgumentNullException due to documentation. We must to think about this case.
What another problems we can got with using of simple Func<...>? Well, you must to know difference between IEnumerable<T> and IQueryable<T> interfaces. In simple words, all operations on IEnumerable causes simple iteratation over all elements (well, it's lazy, IEnumerable really slower than IQueryable). So, for example, combining of Where(filter), Take(100), ToList() on collection that have 10000 elements that are bad for this filter and 400 elements that are good will cause iterating over 10100 elements. If you wrote similar code for IQueryable the request of filtering will send on database server and this server will iterate only ~400 (or 1000, but not 10100), if you have configured indexes on database. So what happens in your code.
var results = ctx.Statements // you are getting DbSet<Statement> that implements interface IQueryable<Statement> (and IQueryable<T> implements IEnumerable<T>)
.Include("StatementDetails") // still IQueryable<Statement>
.Include("StatementDetails.Entry") // still IQueryable<Statement>
.Where(filter) // Cuz your filter is Func<..> and there are no extension methods on IQueryable that accepts Func<...> as parameter, your IQueryable<Statement> casted automatically to IEnumerable<Statement>. Full collection will be loaded in your memory and only then filtered. That's bad
.Take(100) // IEnumerable<Statement>
.Select(s => new StatementSearchResultDTO { .... // IEnumerable<Statement> -> IEnumerable<StatementSearchResultDTO>
}
Okay. Now you understand the problem. So, simple right code for you can be writed in this way:
using (var ctx = new MyContext()) {
results = ctx.Statements
.Include("StatementDetails")
.Include("StatementDetails.Entry")
.AsQueryable();
if (!string.IsNullOrEmpty(request.ItemNumber))
results = results.Where(s => s.StatementDetails.Any(sd => sd.ItemNumber == request.ItemNumber));
if (request.StatusA) {
if (request.StatusB)
results = results.Where(s => s.StatementStatus == StatementStatusType.StatusA ||
s.StatementStatus == StatementStatusType.StatusA);
else
results = results.Where(s => s.StatementStatus == StatementStatusType.StatusA);
}
else {
if (request.StatusB) {
results = results.Where(s => s.StatementStatus == StatementStatusType.StatusB);
}
else {
// do nothing
}
}
results = .Take(100)
.Select(s => new StatementSearchResultDTO{ ....
};
// .. now you can you results.
}
Yeah, totally ugly, but now your database solves how to find Statements that satisfy the filter. Therefore, this request is quickly as possible. Now we must understand what magic happens in code I written upper. Let's compare two examples of code:
results = results.Where(s => s.StatementDetails.Any(sd => sd.ItemNumber == request.ItemNumber));
And this:
Func<Statement, bool> filter = s => s.StatementDetails.Any(sd => sd.ItemNumber == request.ItemNumber);
results = results.Where(filter);
What the difference? Why first is more faster? Answer: when compiler sees first code, it examines that type of results is IQueryable<T> and IEnumerable<T> so that condition inside of brackets can have type Func<Statement, bool> (compiled function) or Expression<Func<Statement, bool>> (data, that can be compiled in function). And compiler chooses Expression (why - really dunno, just chooses). After request of first object query compiled not in C# statement, but in SQL statement and sends to server. Your SQL server can optimize request, because of indexes existing.
Well, the more better way - to write your own expressions. There are different ways to write your own expression, but there is a way to write it with not ugly syntax. The problem that you can't just invoke one expression from another - that doesn't supported by Entity Framework and can be not supported by another ORM's. So, we can use PredicateBuilder by Pete Montgomery: link. And then write two simple extensions on expressions suitable for us.
public static Expression<Func<T, bool>> OrNullable<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
if (first != null && second != null)
return first.Compose(second, Expression.OrElse);
if (first != null)
return second;
if (second != null)
}
And that same for And. And now we can write our filter:
{
Expression<Func<Statement, bool>> filterByStatusA = null;
Expression<Func<Statement, bool>> filterByStatusB = null;
if (request.StatusA)
filterByStatusA = s => s.StatementStatus == StatementStatusType.StatusA;
if (request.StatusB)
filterByStatusB = s => s.StatementStatus == StatementStatusType.StatusB;
Expression<Func<Statement, bool>> filterByStatuses = filterByStatusA.OrNullable(filterByStatusB);
Expression<Func<Statement, bool>> filterByItemNumber = null;
if (!string.IsNullOrEmpty(request.ItemNumber))
filterByItemNumber = s => s.StatementDetails.Any(sd => sd.ItemNumber == request.ItemNumber);
Expression<Func<Statement, bool>> endFilter = filterByItemNumber.And(filterByStatuses);
requests = ...;
if (endFilter != null)
requests = requests.Where(endFilter);
}
You can got a problem, because class ExpressionVisitor in PredicateBuilder in .NET < 4.0 is sealed. You can get write your own ExpressionVisitor or just copy it from this article.
OK, here is the way I have solved it:
filter.And(s => (request.StatusA && s.StatementStatus == StatementStatusType.StatusA) ||
(request.StatusB && s.StatementStatus == StatementStatusType.StautsB) ||
!(request.StatusA || request.StatusB)); //None selected = All selected
Any comments?

linq function to handle : both fields equal or both null or empty

Hi I have a linq query where I compare an object with all other entity stored in my database. Firstname and lastname are mandatory fields so I don't have to check for null. But in the case of street I have to do these checks.
I want to match if both fields are null or empty strings or that they are the same. The below linq query is working fine.
But I was wandering isn't there any way to make it more readable. For example with a custom function like Bool FieldsAreEqualOrBothNullOrEmpty(r.street, request.street)
Can't figure how to do that and if it's possible.
var same =
from r in db.Requests
where r.firstName.ToLower() == request.firstName.ToLower()
&& r.lastName.ToLower() == request.lastName.ToLower()
//Seems long to just compare two fields
&& ( string.IsNullOrEmpty(r.street) && string.IsNullOrEmpty(request.street) )
|| r.street.ToLower() == request.street.ToLower()
select r;
return same;
I would simplify:
var same =
from r in db.Requests
where r.firstName.ToLower() == request.firstName.ToLower()
&& r.lastName.ToLower() == request.lastName.ToLower()
select r;
if(string.IsNullOrEmpty(request.street)) {
same = same.Where(r => string.IsNullOrEmpty(r.street));
} else {
string street = request.street.ToLower();
same = same.Where(r => r.street.ToLower() == street);
}
The nice thing about the this is that it keeps the query simple in each case.
You could use similar logic for the first two if you choose, and it could also be moved to an expression-based utility method. Untested:
public static IQueryable<T> FieldsAreEqualOrBothNullOrEmpty<T>(
this IQueryable<T> source,
Expression<Func<T, string>> member, string value)
{
Expression body;
if (string.IsNullOrEmpty(value))
{
body = Expression.Call(
typeof(string), "IsNullOrEmpty", null, member.Body);
}
else
{
body = Expression.Equal(
Expression.Call(member.Body, "ToLower", null),
Expression.Constant(value.ToLower(), typeof(string)));
}
return source.Where(Expression.Lambda<Func<T,bool>>(
body, member.Parameters));
}
then:
var same = db.Requests
.FieldsAreEqualOrBothNullOrEmpty(x => x.firstName, request.firstName)
.FieldsAreEqualOrBothNullOrEmpty(x => x.lastName, request.lastName)
.FieldsAreEqualOrBothNullOrEmpty(x => x.street, request.street);
You can just call String.Equals but ignore case, using an appropriate StringComparison.
string.equals(r.street, request.street, StringComparison.OrdinalIgnoreCase);
It's bad practice to convert strings to lower-case for comparison purposes, as it won't reliably work in all languages, and is slower than using a comparison which ignores case. See, e.g., this answer
How about creating extension method on string IsEqualOrBothNullOrEmpty -
public static class Extensions
{
public static bool IsEqualOrBothNullOrEmpty(this string firstValue,
string secondValue)
{
return string.IsNullOrEmpty(firstValue) &&
string.IsNullOrEmpty(secondValue)
|| firstValue.ToLower() == secondValue.ToLower();
}
}
And use in your query like this -
var same =
from r in db.Requests
where r.firstName.ToLower() == request.firstName.ToLower()
&& r.lastName.ToLower() == request.lastName.ToLower()
&& r.street.IsEqualOrBothNullOrEmpty(request.Street)
select r;
return same;

How to Refactor LINQ Query to Use Delegate or Expression<Func<T, bool>>

This method works great and generates only 1 query (utilizing .Includes() to eager load).
However, I would like to refactor the AbleToDelete code to be more reusable.
(Using EF4)
public override IEnumerable<AffectProjection> SelectAll(SearchAffects page)
{
IQueryable<Affect> query = BuildSearchQuery(page);
IEnumerable<AffectProjection> results = query.Select(entity => new AffectProjection()
{
AffectID = entity.AffectID,
AffectCode = entity.AffectCode,
AffectName = entity.AffectName,
AbleToDelete = !((entity.Foo1s.Any(pa => !pa.Inactive))
|| (entity.Foo2s.Any(ea => !ea.Inactive))
|| (entity.Foo3s.Any(sa => !sa.Inactive))
|| (entity.Foo4s.Any(spa => !spa.Inactive)))
}).ToArray();
return results;
}
I moved the code into an Expression Func structure but can't figure out how to replace my code that is setting the AbleToDelete property. Advise?
public Expression<Func<Affect, bool>> DelegateExpression = entity =>
!((entity.Foo1s.Any(pa => !pa.Inactive))
|| (entity.Foo2s.Any(ea => !ea.Inactive))
|| (entity.Foo3s.Any(sa => !sa.Inactive))
|| (entity.Foo4s.Any(spa => !spa.Inactive)));
Last but not least, this solution compiles but fails at runtime with error: "NotSupportedException - The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." Trying to use a delegate which isn't supported:
public override IEnumerable<AffectProjection> SelectAll(SearchAffects page)
{
IQueryable<Affect> query = BuildSearchQuery(page);
//Create delegate instance and register method -- single statement
var deleteAbilityAllowed = new CanDelete(GetAbleToDelete);
IEnumerable<AffectProjection> results = query.Select(entity => new AffectProjection()
{
AffectID = entity.AffectID,
AffectCode = entity.AffectCode,
AffectName = entity.AffectName,
AbleToDelete = deleteAbilityAllowed(entity)
}).ToArray();
return results;
}
public delegate bool CanDelete(Affect entity);
public bool GetAbleToDelete(Affect entity)
{
return !((entity.Foo1s.Any(pa => !pa.Inactive))
|| (entity.Foo2s.Any(ea => !ea.Inactive))
|| (entity.Foo3s.Any(sa => !sa.Inactive))
|| (entity.Foo4s.Any(spa => !spa.Inactive)));
}
Please advise and thank you in advance!
LINQKit contains methods that allow you to do this. With it, you can use yout DelegateExpression. To do that, add AsExpandable() to the source of your query and then invoke the Expression using Invoke():
var expression = DelegateExpression;
var results = query.AsExpandable().Select(entity => new AffectProjection()
{
AffectID = entity.AffectID,
AffectCode = entity.AffectCode,
AffectName = entity.AffectName,
AbleToDelete = expression.Invoke(entity)
}).ToArray();
Be careful though, it seems you can't use the expression directly from the field, it has to be from a local variable.

Categories

Resources