How to pass an external parameter to LINQ where clause in CRM - linq

I have a LINQ query which works fine as for stand alone lists but fails for CRM
var lst = new List<bool?>();
lst.Add(null);
lst.Add(true);
lst.Add(false);
bool IsWet = false;
var newlst = from exch_HideVoiceSignature in lst where
(((exch_HideVoiceSignature!=null && exch_HideVoiceSignature==false
|| exch_HideVoiceSignature== null) )&& !IsWet) select exch_HideVoiceSignature;
newlst.Dump();
var question = from q in exch_questionSet where ((q.exch_HideVoiceSignature != null
&& q.exch_HideVoiceSignature.Value == 0 )|| q.exch_HideVoiceSignature == null )
&& !IsWet select q.exch_HideVoiceSignature;
question.FirstOrDefault().Dump();
As you can see I can pass the variable IsWet to LINQ query for a standard list fine and get values for first list. But when I execute the same for second list, I get the following error
Invalid 'where' condition. An entity member is invoking an invalid property or method

The CRM LINQ provider won't support the evaluation you attempting. It only supports evaluation of where criteria is evaluating an entity field.
That's not a problem. Since you want the LINQ query to only use the where clause if IsWet is false (correct me if I'm wrong on that.) So we simply do the evaluation to determine if the where clause should be added or not. Then execute your query.
var question = from q in exch_questionSet
select q.exch_HideVoiceSignature;
if (!IsWet)
{
question.Where(x => ((x.exch_HideVoiceSignature != null
&& x.exch_HideVoiceSignature.Value == 0) || x.exch_HideVoiceSignature == null));
}
question.FirstOrDefault().Dump();

I am constantly confronted with that problem.
Try to "detach" (for example call .ToArray()) your query (while it is "clear") from CRM and then filter query using external parameter. This should help.
var question =
(from q in exch_questionSet
where (
(q.exch_HideVoiceSignature != null && q.exch_HideVoiceSignature.Value == 0 ) ||
q.exch_HideVoiceSignature == null )
select q.exch_HideVoiceSignature
).ToArray().Where(q => !IsWet);
question.FirstOrDefault().Dump();
UPDATE
If you are using IsWet flag to control blocks of conditions (enable and disable them from the one point in the code) then probably you may be interested in class named PredicateBuilder which allows you to dynamically construct predicates.

Just because I had an existing query with lot of other joins etc. and I wanted to pass this additional parameter to it I ended up using a var statement which dumps the rows to a list and applies the where clause in the same statement
bool IsWet =true ;
var question = ...existing query ...
select new {
...existing output ...,
Wet =q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080001,
Voice = q.exch_HideVoiceSignature == null ||
(q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080000) ,
}
;
var qq = IsWet ?
question.ToList().Where(X=> X.Wet ) :
question.ToList().Where(X=> X.Voice );
qq.FirstOrDefault().Dump();

Related

How to compare IEnumerable<string> for null in Linq query

For the following query:
var result = from sch in schemeDashboard
join exp in Expenditure on sch.schemeId equals exp.SchemeCode
into SchExpGroup
where sch.SectorDepartmentId == selectedDepartmentId &&
sch.YearCode == StateManager.CurrentYear
orderby sch.ADPId
select new
{
ModifiedAmounts = SchExpGroup.Select(a => a.ModifiedAmounts),
ProjectName = sch.schemeName,
ADPNo = sch.ADPId,
Allocation = sch.CurrentAllocation,
Expenditures = from expend in SchExpGroup
where expend.YearCode == StateManager.CurrentYear &&
expend.DepartmentId == selectedDepartmentId &&
InvStatus.Contains(expend.Status)
orderby expend.ADPId
group expend by expend.InvoiceId
};
I want to filter the above query on a condition so that result gives only those records where "ModifiedAmounts" are not null. I have tried as follow:
if (rbList2.SelectedIndex == 6)
{
result = result.Where(a => a.ModifiedAmounts != null));
}
but this gives error as:
Cannot compare elements of type
'System.Collections.Generic.IEnumerable`1'. Only primitive types,
enumeration types and entity types are supported.
Any suggestions as I am lost as how to rephrase the filtered query.
I think the problem is that ModifiedAmounts will never be null. Select will return an empty list. Unless SchExpGroup is null in which case you will get a null reference exception.
Try changing your code to
result = result.Where(a => a.ModifiedAmounts.Any());
if (rbList2.SelectedIndex == 6)
{
result = result.Where(a => a.!ModifiedAmounts.Any());
}

Linq with Logic

I have simple Linq statement (using EF4)
var efCars = (from d in myentity.Cars
where d.CarName == inputCar.CarName
&& d.CarIdNumber == inputCar.IdNumber
&& d.Make == inputCar.Make
select d.Car);
I want it to be smarter so that it will only query across one or more of the 3 fields IF they have values.
I can do a test before, and then have a separate linq statement for each permutation of valyes for inputcar
(i.e. one for all 3, one for if only carname has a value, one for if carname AND CarIdNumber has a value etc etc)
but there must be a smarter way
Thanks!
If "has no value" means null then you can use the null coalescing operator ?? to say take the first value if populated, otherwise take the second:
var efCars = (from d in myentity.Cars
where d.CarName == (inputCar.CarName ?? d.CarName
&& d.CarIdNumber == (inputCar.IdNumber && d.CarIdNumber)
&& d.Make == (inputCar.Make && d.Make)
select d.Car);
This basically says if a value exists it must match, otherwise treat it as matching
However if instead you're saying "when a special value (empty string) ignore it, otherwise match" then you can do one of two approaches (or possibly more!):
where (inputCar.CarName == "" || d.CarName == inputCar.CarName)
where (string.IsNullOrEmpty(inputCar.CarName) || d.CarName == inputCar.CarName)
For performance (when dealing with database queries) it can sometimes be beneficial to let EF generate queries based on the filters, instead of using one generic query. Of course you will need to profile whether it helps you in this case (never optimize prematurely), but this is how it would look if you dynamically build your query:
var efCars =
from car in myentity.Cars
select car;
if (inputCar.CarName != null)
{
efCars =
from car in efCars
where care.CarName == inputCar.CarName
select car;
}
if (inputCar.IdNumber != null)
{
efCars =
from car in efCars
where care.CarIdNumber == inputCar.IdNumber
select car;
}
if (inputCar.Make != null)
{
efCars =
from car in efCars
where care.Make == inputCar.Make
select car;
}
where (inputCar.CarName != null || d.CarName == inputCar.CarName) &&...

Linq Where Clause Change based on Parameters

I have a linq statement that returns a list of records based on where clause
This where clause checks for two parameter values.
Out of which one parameter is optional.
so i need a suggestions if i can switch my where clause based on the optional Parameter
something like this
if(locid==0)
{
where (p.CustomerID == custid)
}
else{
where (p.CustomerID == custid) & (p.LocationID == locid )
}
can any one help me how can i get this work.
thanks
You could try writing it like this:
where (p.CustomerID == custid) && (locid == 0 || p.LocationID == locid )
Yes - queries can be composed (although you don't need this for this particular case as #rsbarro pointed out):
var query = p;
if(locid==0)
query = query.Where( p =>p.CustomerID == custid);
else
query = query.Where( p =>p.CustomerID == custid & p.LocationID == locid);
//any other conditions
As BrokenGlass mentioned, you should use composition:
IQueryable<Foo> query = unfiltered.Where(p => p.CustomerID == custId);
if (locid != 0)
{
query = query.Where(p => p.LocationID == locid);
}
Note that the query is not executed until you start reading data from it, so you needn't worry about this making multiple requests.
It looks like in your original post you were trying to use query syntax piecemeal - that won't work, but the "dot notation" is pretty simple here. You can always create your initial query using a query expression if you want - again, that query won't be executed immediately anyway.

In Operator in Linq

I tried to use the suggestion provided here for using In operator in linq but, i am not able to convert my requirement into LINQ statement.
Below is the SQL query which i need to convert to Linq
select *
from navigator_user_field_property
where user_id = 'albert'
and field_id in (
select field_id
from navigator_entity_field_master
where entity_id = 1
and use_type = 0)
order by field_id
I want this to be converted to a Efficient Linq.
Most of the answers deal with the predetermined list of string array which is not working in my case.
Thanks
Looks like a join to me:
var query = from navigator in db.NavigatorUserFieldProperties
where navigator.UserId == "albert"
join field in db.NavigatorEntityFieldMasters
.Where(f => f.EntityId == 1 && f.UseType == 0)
on navigator.FieldId equals field.FieldId
select navigator;
Note that this will return the same value multiple times if there are multiple fields with the same ID - but I suspect that's not the case.
You could do a more literal translation like this:
var query = from navigator in db.NavigatorUserFieldProperties
where navigator.UserId == "albert" &&
db.NavigatorEntityFieldMasters
.Where(f => f.EntityId == 1 && f.UseType == 0)
.select(f => f.FieldId)
.Contains(navigator.FieldId)
select navigator;
... and that may end up translating to the same SQL... but I'd personally go with the join.
Here is an efficient and readable LINQ query:
var fields =
from field in db.navigator_entity_field_masters
where field.entity_id == 1 && field.user_type == 0
select field;
var properties =
from property in db.navigator_user_field_properties
where property.user_id == "albert"
where fields.Contains(property.field)
select property;
Look mama!! Without joins ;-)

Complex Expressions in a LINQ Where Clause

I was wondering if it is possible to include inner variables or delegates in linq statements?
I currently am using Linq to XML with XPath extensions and am using a where clause on an element that I cannot guarantee will exist.
Here is a sample of what I mean:
var result =
from record in xml.Root.XPathSelectElements("record")
where ...
select record;
I want the where to be something like:
where
{
var element = record.XPathSelectElement("element[#type='sometype']");
return (element != null && element.Value.Contains("keyword"));
}
You want the "let" keyword in Linq. Something like this?
var result =
from record in xml.Root.XPathSelectElements("record")
let element = record.XPathSelectElement("element[#type='sometype']")
where (element != null && element.Value.Contains("keyword"))
select record;
You could use a "let" clause here;
from record in xml.Root.XPathSelectElements("record")
let element = record.XPathSelectElement("element[#type='sometype']")
where element != null && element.Value.Contains("keyword")
select record;
I don't know the query syntax well enough to say for sure, but this would be trivial with the functional syntax:
var result = xml.Root.XPathSelectElements("record").Where(record => {
var element = record.XPathSelectElement("element[#type='sometype']");
return (element != null && element.Value.Contains("keyword"));
});

Resources