Nullable filters in XRM where clause - c#

I'm using the XRM (early bound) types in a WCF project so I have access to the CRM model and can use LINQ queries. But I've been running into a problem described here, it's the limitations on the where clause specific to XRM LINQ:
where [clause limitations]
The left side of the clause must be an attribute name and the right side of
the clause must be a value. You cannot set the left side to a constant. Both
the sides of the clause cannot be constants.
Supports the String functions Contains, StartsWith, EndsWith, and Equals.
One requirement that keeps popping up is when a parameter is null, all entities should be returned otherwise filter by the parameter. But I can't think of a way to do this without breaking the requirements above, or writing multiple queries to handle the scenario when it's null.
this is an example of one of my queries, the typeFilter == null is the problem here is I've used a constant on the LHS. In my real code there's a guard clause that points typeFilter == null to another query but I now have to add a start/end date filter (both nullable) and I cannot express how much I don't want to write a query for every combination of nullables.
private IQueryable<EventInfo> getAllEvents( DataContext context, EventType? typeFilter )
{
return (
from evt in context.new_eventSet
where
( evt.statecode == new_eventState.Active ) &&
( typeFilter == null || evt.new_EventType.Value == (int) typeFilter.Value )
select new EventInfo()
{
ID = evt.Id,
EventType = (EventType) evt.new_EventType.Value
...
} );
}

How about:
if (typeFilter == null)
{
return (
from evt in context.new_eventSet
where
( evt.statecode == new_eventState.Active )
select new EventInfo()
{
ID = evt.Id,
EventType = (EventType) evt.new_EventType.Value
...
} );
}
else
{
return (
from evt in context.new_eventSet
where
( evt.statecode == new_eventState.Active ) &&
evt.new_EventType.Value == (int) typeFilter.Value )
select new EventInfo()
{
ID = evt.Id,
EventType = (EventType) evt.new_EventType.Value
...
} );
}

I've answered my own question! sometimes you just need a place to vent your problems before you get it.
the trick was to not use LINQ syntax:
private IQueryable<EventInfo> getAllEvents( DataContext context, EventType? typeFilter, DateTime? startDateFilter, DateTime? endDateFilter )
{
var result = context.new_eventSet
// active records
.Where( evt => evt.statecode == new_eventState.Active )
// is publish-able
.Where( ..etc.. );
if ( typeFilter != null )
{
// filter by type
result = result.Where( evt => evt.new_EventType.Value == (int) typeFilter.Value );
}
if( startDateFilter != null)
{
// filter by startDate
result = result.Where(evt => evt.new_StartDate > startDateFilter.Value);
}
if( endDateFilter != null)
{
// filter by endDate
result = result.Where(evt => evt.new_StartDate < endDateFilter.Value);
}
return result.Select( evt => new EventInfo()
{
ID = evt.Id,
EventType = (EventType) evt.new_EventType.Value,
...
} );
}

If you want to use the Linq syntax, it is possible to construct a query dynamically using LinqKit.
I have used it for this purpose on the Dynamics CRM project which I'm currently working on, and it does the job very well.
Please refer to the following answer, which is where I got the idea: https://stackoverflow.com/a/5152946/344988

Related

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.

MongoDB Select with QueryBuilder

i'm trying to select values from my database, but currently i'm unable to to it and although i know its the fact that the method doesnt except the QueryBuilder class as a parameter, i dont know what to do about it. I only found solutions for querys with one parameter or all parameters are not null. In my case i've a List with ID, and 4 parameters which dont have to be passed to the function so they could be null.
My current code looks like this.
collection = db.GetCollection<Datapoint>("test");
var query = new QueryBuilder<Datapoint>();
var queryattributes = new List<IMongoQuery>();
var ids = new List<IMongoQuery>();
// Add all Attributes if there
if (fromdate != null)
{
BsonDateTime from = BsonDateTime.Create(fromdate);
queryattributes.Add(Query.GTE("UTCTimestamp", from));
}
if (to != null)
{
BsonDateTime bto = BsonDateTime.Create(to);
queryattributes.Add(Query.LTE("UTCTimestamp", bto));
}
if (evId != null)
{
queryattributes.Add(Query.EQ("EvId", evId));
}
if (evType != null)
{
queryattributes.Add(Query.EQ("EvType", evType));
}
// Add all ID's
Parallel.ForEach(idList, data =>
{
lock (query)
{
ids.Add(Query.EQ("CId", data));
}
});
// But everything in the Query
query.Or(ids);
// Add Queryattributes if there
if (queryattributes.Count > 0)
{
query.And(queryattributes);
}
var result = collection.FindAs<Datapoint>(query);
I'm trying to do it without Linq, since i found countless of test, which say that linq is much much slower, and since i want to run it as an Databasetest, i kinda need the performace to execute alot of querys.
The Linq query looks like this
var query2 =
from e in collection.AsQueryable<Datapoint>()
where idList.Contains(e.CId)
&& (evtId == null || e.EvId == evId)
&& (evType == null || e.EvType == evType.Value)
&& (fromdate == null || Query.GTE("UtcTimestamp", BsonDateTime.Create(fromdate)).Inject())
&& (to == null || Query.LT("UtcTimestamp", BsonDateTime.Create(to)).Inject())
select e;
The QueryBuilder doesn't save a query inside it. You use it to generate a IMongoQuery and then use that query to actually query the database.
It seems the end of your code should look like this;
// But everything in the Query
IMongoQuery mongoQuery = query.Or(ids);
// Add Queryattributes if there
if (queryattributes.Count > 0)
{
mongoQuery = query.And(queryattributes);
}
var result = collection.FindAs<Datapoint>(mongoQuery);

How do i get this conditional include projection to instantiate the "premis" entity-object property of the ref_calendar_premis entity-object?

I'm working on my first EntityFramework-solution, and I'm stumped.
When I'm iterating through the resulting "calendar"-entity objects, the property calendar.ref_calendar_premisis.premisis is un-instantiated (null). I understand why, I deactivated lazy-loading because i wanted to control the conditional "includes" in a syntax-tree projection like so:
private List<CalendarBlockDTO> FillUserCalendar(DateTime start, DateTime end, int uid, bool everything)
{
var result = new List<CalendarBlockDTO>();
using (var db = new ViggoEntities())
{
//We need to disable lazyloading to use the "expression tree" syntax
db.Configuration.LazyLoadingEnabled = false;
//flip our "everything" so we can compare it to our "special" column
int specialScope = Convert.ToInt32(!everything);
//Build a query "Projection" with "expression tree" syntax
var query = from c in db.calendars
select new
{
calendarEntry = c,
createdByUser = c.MadeByUser,
premisesBookings = c.ref_calendar_premises.Where
(
rcp => rcp.deleted == 0 &&
(
//started before the start-parameter AND ended after start-parameter
(rcp.timestart < start && rcp.timeend > start) ||
//OR startet before the end-parameter AND ended after the end-parameter
(rcp.timestart < end && rcp.timeend > end) ||
//OR startet before the start-parameter AND ended after the end-paremeter
(rcp.timestart < start && rcp.timeend > end) ||
//OR startet after the start-parameter AND ended before the end-parameter
(rcp.timestart > start && rcp.timeend < end)
)
),
attendingGroups = c.ref_groups_calendar.Where
(
rug => rug.deleted == 0
),
groups = c.ref_groups_calendar.Select( rgc => rgc.usergroup ),
////Assignments not implemented yet
////assignments = c.
schedules = c.ref_calendar_schedule.Where
(
sch => sch.deleted == 0
)
};
var calEntries =
query.ToArray().Select(c => c.calendarEntry).
Where(
//If only special requested, show only special
c => c.special >= specialScope &&
//If not "MadeInInfo", show for creator as well
(c.madeininfo==0 && c.made_by == uid) ||
//Else, show to involved users
(c.ref_groups_calendar.Any(rgc => rgc.usergroup.ref_users_groups.Any(rug => rug.userid == uid)))
);
foreach (var calendar in calEntries)
{
//I WANT THIS TO NOT THROW AN EXCEPTION, PREMIS SHOULD NOT BE NULL
if (calendar.name == "Dinner with Allan" && calendar.ref_calendar_premises.Any(rcp => rcp.premis == null))
throw new Exception("Premis not instantiated!");
result.AddRange(CalendarToCalendarBlockDTOs(calendar));
}
}
return result;
}
I tried adding something like:
...
room = c.ref_calendar_premises.Select(r => r.premis),
...
... But to no avail. A room has been booked for the "Dinner with Allan" event in our test data, but i cant seem to get it to load the premis-entyties.
I have no previous experience with EntityFramework, LINQ to SQL or any other ORM's, so I might be missing something plainly obvious.
Any suggestions?
I twisted the arm of our DB-responsible, and turns out premisisid is null for all rows because of a conversion error (i was looking at testdata documentation, not the actual data).
So thanks for the input and your time, I'll just show myself out 0_0

Generated query for tinyint column introduces a CAST to int

I am querying a tinyint column and entity-framework generates a SELECT query that introduces a CAST to INT for this column even when the value that I am using in the WHERE clause is of the type byte.
Looking the Model, the generated Type for my tinyint column is byte.
Looking the code:
byte byteValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.TinyintColumn == byteValue
select r;
Looking the generated query:
SELECT [Extent1].[TinyintColumn] AS [TinyintColumn] WHERE #p__linq__0 = CAST( [Extent1].[TinyintColumn] AS int)
I have strict restrictions in the performance so I don't want those CAST in any select.
So my question whould be, is there any way to avoid this CAST over the column tinyint? or am I doing something wrong?
Thanks in advance.
If you use IList<T>.Contains with a List<byte> the Entity Framework won't cast.
List<byte> byteValue = new List<byte> { 6 };
var entityList = from r in rep.DataContext.FooTable
where byteValue.Contains(r.TinyintColumn)
select r;
I ran into the same problem and blogged about it.
My colleague found very nice trick to overcome this issue on Entity Framework 4.0.
Works for smallint, I didn't try on tinyint.
Insteal of equals (==) - use Contains() operator which was implemented with EF 4.0.
For example:
say you have the column SmallIntColumn.
instead of:
short shortValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.SmallIntColumn == shortValue
select r;
use
short[] shortValue = new short[] { 6 };
var entityList = from r in rep.DataContext.FooTable
where shortValue.Contains(r.SmallIntColumn)
select r;
Check the SQL generated - it is now without the CAST!
And from my tests - the execution plan used my (filtered) index on the column just perfectly.
Hope it helped.
Shlomi
The contains solution may not be optimized by the DB if the smallint comparison is one segment of the filtering on multiple columns and there is an index matching the those columns. I verified that using the Equals method fixed this problem with the SmallInt type, at least on EF6.
Instead of
short shortValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.SmallIntColumn == shortValue
select r;
use
short shortValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.SmallIntColumn.Equals(shortValue)
select r;
The CAST will affect performance because indexes won't be used on TinyintColumn
This is combination of points 2 and 4 in "Ten Common SQL Programming Mistakes". CAST is a function on a column, and without it you'll have a datatype mismatch anyway
#p__linq__0 should be tinyint or explicitly CAST.
However, it could be LINQ doesn't like tinyint primary keys according to MS Connect and (SO) asp.net mvc linq sql problem
You could "byte" the bullet (sorry) and use smallint...
I'm posting the solution I've taken for this problem.
It seems that EntityFramework 4.0 always generates queries with CAST in tinyint or smallint fields. So for performance optimization, I have decided to change to INT those fields to avoid the CAST and I have changed the size of other nvarchar fields that I still could decrease from nvarchar(50) to nvarchar(30). So at the end I have changed the size of the row from 143 Bytes to 135 Bytes.
If you have an Sql table column data type of tinyint , the corresponding POCO objects should have a property of type byte. This will work for you. Else you when you are iterating through the LINQ object , it will throw an error stating that unable to convert byte type to say int or whatever as you may have defined for the property.
I just verified with EF 4.3 Code First Approach , Everything went well.
I ran into the exact same problem while using EF with a lambda expression. Beefing up the datatype to an int is not a solution and even bad practice. What i found and as other reported here is that you do get correct code when you take a more clumsy aproach, like:
SomeEntity.FindBy( i => new List { 1 }.Contains( i.TinyintColumn ) )
But when then you run into other issues with more then one value to match against. The following will not use parameterised query values, and but just inline them into the query body!
SomeEntity.FindBy( i => new List { 1, 2 }.Contains( i.TinyintColumn ) )
That is not as bad at the original problem, but still not good as it means the database has to complile a plan for every combination of values that you throw at it and makes performance analysis next to impossible as there is no proper aggregation of execution times. It also has some performance effects you rather not see in high load enviroments!
Do not get me started on what these kind of behaviors/anti-patterns would do to char/nchar datatypes and their effect on indexes. As i see it, centralizing everything around the datatype system C# implements is both limited and causes major issues.
My view on EF is that very basic queries on well modelled tables are transformed to bad SQL code and EF follows anti-patterns. It is not something I find impressive in the light of the hype and the added complexity in development EF brings! I wont go into that here right now, as that would be a whole different discussion!
Pick any of the above solutions, but know the drawbacks before using them. Maybe version 10 of EF will solve the problem to a degree, i don't hold my breath however.
If you like to preserve the logic you can use expression rewrite method.
The code will be like
db.MyEntities.Where(e => e.Id == i).FixIntCast()
and you keep the application logic as is.
Try more complex version of IntCastFixExtension :
namespace System.Linq {
/// <summary>
/// author: Filip Sielimowicz inspired by
/// http://www.entityframework.info/Home/SmallIntProblem
/// </summary>
public static class IntCastFixExtension {
public static IQueryable<T> FixIntCast<T>(this IQueryable<T> q, bool narrowMemberExpr = true, bool narrowConstantExpr = true) {
var visitor = new FixIntCastVisitor() {
narrowConstExpr = narrowConstantExpr,
narrowMembExpr = narrowMemberExpr
};
Expression original = q.Expression;
var expr = visitor.Visit(original);
return q.Provider.CreateQuery<T>(expr);
}
private class FixIntCastVisitor : ExpressionVisitor {
public bool narrowConstExpr;
public bool narrowMembExpr;
protected override Expression VisitBinary(BinaryExpression node) {
bool eq = node.NodeType == ExpressionType.Equal;
bool neq = node.NodeType == ExpressionType.NotEqual;
if (eq || neq) {
var leftUncasted = ReducePossiblyNotNecessaryIntCastExpr(node.Left);
var rightUncasted = ReducePossiblyNotNecessaryIntCastExpr(node.Right);
var rightConst = node.Right as ConstantExpression;
if (leftUncasted == null) {
return base.VisitBinary(node);
}
if (rightUncasted != null) {
if (NarrowTypesAreCompatible(leftUncasted.Type, rightUncasted.Type)) {
// Usuwamy niepotrzebne casty do intów występujące po obu stronach equalsa
return eq ? Expression.Equal(leftUncasted, rightUncasted) : Expression.NotEqual(leftUncasted, rightUncasted);
}
} else if (rightConst != null) {
// Zamiast casta argumentu z lewej w górę do inta (tak zrobił linq2entity)
// zawężamy występującą po prawej stałą typu 'int' do typu argumentu z lewej
if (narrowConstExpr && (rightConst.Type == typeof(int) || rightConst.Type == typeof(int?))) {
var value = rightConst.Value;
var narrowedValue = value == null ? null : Convert.ChangeType(rightConst.Value, leftUncasted.Type);
Expression narrowedConstExpr = Expression.Constant(narrowedValue, leftUncasted.Type);
return eq ? Expression.Equal(leftUncasted, narrowedConstExpr) : Expression.NotEqual(leftUncasted, narrowedConstExpr);
}
} else if (node.Right.NodeType == ExpressionType.MemberAccess) {
// Jak po prawej mamy wyrażenie odwołujące się do zmiennej typu int to robimy podobnie jak przy stałej
// - zawężamy to, zamiast upcasta do inta z lewej.
if (narrowMembExpr) {
var rightMember = node.Right;
var narrowedMemberExpr = Expression.Convert(rightMember, leftUncasted.Type);
return eq ? Expression.Equal(leftUncasted, narrowedMemberExpr) : Expression.NotEqual(leftUncasted, narrowedMemberExpr);
}
}
}
return base.VisitBinary(node);
}
private bool NarrowTypesAreCompatible(Type t1, Type t2) {
if (t1 == typeof(short?)) t1 = typeof(short);
if (t2 == typeof(short?)) t2 = typeof(short);
if (t1 == typeof(byte?)) t1 = typeof(byte);
if (t2 == typeof(byte?)) t2 = typeof(byte);
return t1 == t2;
}
private bool IsNullable(Type t) {
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
private Expression CorrectNullabilityToNewExpression(Expression originalExpr, Expression newExpr) {
if (IsNullable(originalExpr.Type) == IsNullable(newExpr.Type)) {
return newExpr;
} else {
if (IsNullable(originalExpr.Type)) {
Type nullableUncastedType = typeof(Nullable<>).MakeGenericType(newExpr.Type);
return Expression.Convert(newExpr, nullableUncastedType);
} else {
Type notNullableUncastedType = Nullable.GetUnderlyingType(newExpr.Type);
return Expression.Convert(newExpr, notNullableUncastedType);
}
}
}
private Expression ReducePossiblyNotNecessaryIntCastExpr(Expression expr) {
var unnecessaryCast = expr as UnaryExpression;
if (unnecessaryCast == null ||
unnecessaryCast.NodeType != ExpressionType.Convert ||
!(unnecessaryCast.Type == typeof(int) || unnecessaryCast.Type == typeof(int?))
) {
// To nie jest cast na inta, do widzenia
return null;
}
if (
(unnecessaryCast.Operand.Type == typeof(short) || unnecessaryCast.Operand.Type == typeof(byte)
|| unnecessaryCast.Operand.Type == typeof(short?) || unnecessaryCast.Operand.Type == typeof(byte?))
) {
// Jest cast z shorta na inta
return CorrectNullabilityToNewExpression(unnecessaryCast, unnecessaryCast.Operand);
} else {
var innerUnnecessaryCast = unnecessaryCast.Operand as UnaryExpression;
if (innerUnnecessaryCast == null ||
innerUnnecessaryCast.NodeType != ExpressionType.Convert ||
!(innerUnnecessaryCast.Type == typeof(int) || innerUnnecessaryCast.Type == typeof(int?))
) {
// To nie jest podwójny cast między intami (np. int na int?), do widzenia
return null;
}
if (
(innerUnnecessaryCast.Operand.Type == typeof(short) || innerUnnecessaryCast.Operand.Type == typeof(byte)
|| innerUnnecessaryCast.Operand.Type == typeof(short?) || innerUnnecessaryCast.Operand.Type == typeof(byte?))
) {
// Mamy podwójny cast, gdzie w samym środku siedzi short
// Robimy skrócenie, żeby intów nie produkował zamiast short -> int -> int?
// powinno ostatecznie wychodzić short -> short czyli brak castowania w ogóle.
return CorrectNullabilityToNewExpression(unnecessaryCast, innerUnnecessaryCast.Operand);
}
}
return null;
}
}
}
}
The db column is probably nullable.
Try this: r.TinyintColumn.Value == byteValue

Dynamic where condition in LINQ

I have a scenario where I have to use a dynamic where condition in LINQ.
I want something like this:
public void test(bool flag)
{
from e in employee
where e.Field<string>("EmployeeName") == "Jhom"
If (flag == true)
{
e.Field<string>("EmployeeDepartment") == "IT"
}
select e.Field<string>("EmployeeID")
}
I know we can't use the 'If' in the middle of the Linq query but what is the solution for this?
Please help...
Please check out the full blog post: Dynamic query with Linq
There are two options you can use:
Dynamic LINQ library
string condition = string.Empty;
if (!string.IsNullOrEmpty(txtName.Text))
condition = string.Format("Name.StartsWith(\"{0}\")", txtName.Text);
EmployeeDataContext edb = new EmployeeDataContext();
if(condition != string.empty)
{
var emp = edb.Employees.Where(condition);
///do the task you wnat
}
else
{
//do the task you want
}
Predicate Builder
Predicate builder works similar to Dynamic LINQ library but it is type safe:
var predicate = PredicateBuilder.True<Employee>();
if(!string.IsNullOrEmpty(txtAddress.Text))
predicate = predicate.And(e1 => e1.Address.Contains(txtAddress.Text));
EmployeeDataContext edb= new EmployeeDataContext();
var emp = edb.Employees.Where(predicate);
difference between above library:
PredicateBuilder allows to build typesafe dynamic queries.
Dynamic LINQ library allows to build queries with dynamic Where and OrderBy clauses specified using strings.
So, if flag is false you need all Jhoms, and if flag is true you need only the Jhoms in the IT department
This condition
!flag || (e.Field<string>("EmployeeDepartment") == "IT"
satisfies that criterion (it's always true if flag is false, etc..), so the query will become:
from e in employee
where e.Field<string>("EmployeeName") == "Jhom"
&& (!flag || (e.Field<string>("EmployeeDepartment") == "IT")
select e.Field<string>("EmployeeID")
also, this e.Field<string>("EmployeeID") business, smells like softcoding, might take a look into that. I guess
from e in employee
where e.EmployeeName == "Jhom"
&& (!flag || (e.EmployeeDepartment == "IT")
select e.EmployeeID
would be more compact and less prone to typing errors.
EDIT: This answer works for this particular scenario. If you have lots of this kinds of queries, by all means investingate the patterns proposed in the other answers.
You can chain methods :
public void test(bool flag)
{
var res = employee.Where( x => x.EmployeeName = "Jhom" );
if (flag)
{
res = res.Where( x => x.EmployeeDepartment == "IT")
}
var id = res.Select(x => x.EmployeeID );
}
from e in employee
where e.Field<string>("EmployeeName") == "Jhom" &&
(!flag || e.Field<string>("EmployeeDepartment") == "IT")
select e.Field<string>("EmployeeID")
You can call LINQ methods explicitly and chain them conditionally.
public IEnumerable<string> FilterEmployees (IEnumerable<Employee> source, bool restrictDepartment)
{
var query = source.Where (e => e.Field<string>("EmployeeName") == "Jhom");
if (restrictDepartment) // btw, there's no need for "== true"
query = query.Where (e => e.Field<string>("EmployeeDepartment") == "IT");
return query.Select (e => e.Field<string>("EmployeeID"));
}

Categories

Resources