Dynamic linq query with dynamic where conditions and from conditions - linq

public GetApplicants(string Office,
int Id,
List<int> cfrparts,
List<int> expertiseAreaIds,
List<int> authIds,
List<int> specIds)
{
bool isAuthIdsNull = authIds == null;
authIds = authIds ?? new List<int>();
bool isSpecIdNull = specIds == null;
enter code here
var query =
from application in Apps
from cfr in application.cfr
from exp in cfr.Aoe
from auth in exp.Auth
from spec in exp.Special
where application.Design.Id == 14
where (iscfrpart || cfrPartIds.Contains(cfr.CfrP.Id))
where (isexp || expertiseAreaIds.Contains(exp.Aoe.Id))
where (isAuthIdsNull || authIds.Contains(auth.Auth.Id))
where (isSpecIdNull || specIds.Contains(spec.Special.Id))
where application.Office.Text.Contains(Office)
where application.D.Id == Id
select application.Id;
How can i make this query dynamic. If I have only Id and Office values It should still give me the resultset based on the avaliable values. Cureently its not giving me the result.

Instead of doing multiple calls to where, use &&
var query =
from Apps
where (iscfrpart || cfrPartIds.Contains(Apps.cfr.CfrP.Id))
&& (isexp || expertiseAreaIds.Contains(Apps.cfr.Aoe.Id))
&& (isAuthIdsNull || authIds.Contains(Apps.cfr.Aoe.Auth.Id))
&& (isSpecIdNull || specIds.Contains(Apps.cfr.Aoe.Special.Id))
&& Apps.Office.Text.Contains(Office)
&& Apps.D.Id == Id
select application.Id;
Additionally, this clause application.D.Id == 14 will cause 0 results when combined with this one: application.D.Id == Id if the passed in Id does not equal 14. You may want to delete that first clause.
Edit: updated your from clause, but I still don't think this will work because your table structure seems off.

Dynamic querying isn't required to solve this problem. You can write code that constructs the query.
Make a method that constructs your filter based on the information you have.
public Expression<Func<Application, bool>> GetFilterForCFR(List<int> cfrParts)
{
if (cfrParts == null || !cfrParts.Any())
{
return app => true;
}
else
{
return app => app.cfr.Any(cfr => cfrParts.Contains(cfr.cfrPId));
}
}
Then, you can construct the query using the expression.
var query = Apps;
var cfrFilter = GetFilterForCFR(cfrParts);
query = query.Where(cfrFilter);
//TODO apply the other filters
var finalquery = query.Select(app => app.Id);

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());
}

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

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();

Distinct keyword in linq query

my linq query returns duplicate records like below, how i have to use distinct keyword in this linq query.
var draft_recieved = from df in _DataContext.tblDrafts
from dfBody in _DataContext.DraftBodies
from sendUser in _DataContext.tblSends
where (df.DraftId == dfBody.DraftID) && (df.DraftId == sendUser.DraftId) &&
(sendUser.ToEmailId == (Guid)Membership.GetUser().ProviderUserKey)
select new
{
subject = dfBody.Subject,
draftid = df.DraftId
};
.Distinct() has to be applied as an extension method.
var draft_recieved = (from df in _DataContext.tblDrafts
from dfBody in _DataContext.DraftBodies
from sendUser in _DataContext.tblSends
where (df.DraftId == dfBody.DraftID) && (df.DraftId == sendUser.DraftId) &&
(sendUser.ToEmailId == (Guid)Membership.GetUser().ProviderUserKey)
select new
{
subject = dfBody.Subject,
draftid = df.DraftId
}).Distinct();

How to join results from two different sets in LINQ?

I get some data about customers in my database with this method:
public List<KlientViewModel> GetListOfKlientViewModel()
{
List<KlientViewModel> list = _klientRepository.List().Select(k => new KlientViewModel
{
Id = k.Id,
Imie = k.Imie,
Nazwisko = k.Nazwisko,
Nazwa = k.Nazwa,
SposobPlatnosci = k.SposobPlatnosci,
}).ToList();
return list;
}
but also I have another method which counts value for extra field in KlientViewModel - field called 'Naleznosci'.
I have another method which counts value for this field based on customers ids, it looks like this:
public Dictionary<int, decimal> GetNaleznosc(List<int> klientIds)
{
return klientIds.ToDictionary(klientId => klientId, klientId => (from z in _zdarzenieRepository.List()
from c in z.Klient.Cennik
where z.TypZdarzenia == (int) TypyZdarzen.Sprzedaz && z.IdTowar == c.IdTowar && z.Sprzedaz.Data >= c.Od && (z.Sprzedaz.Data < c.Do || c.Do == null) && z.Klient.Id == klientId
select z.Ilosc*(z.Kwota > 0 ? z.Kwota : c.Cena)).Sum() ?? 0);
}
So what I want to do is to join data from method GetNaleznosc with data generated in method GetListOfKlientViewModel. I call GetNaleznosc like this:
GetNaleznosc(list.Select(k => k.Id).ToList())
but don't know what to do next.
Having obtained the dictionary:
var dict = GetNaleznosc(list.Select(k => k.Id).ToList());
You can now efficiently look up the decimal value of Naleznosci for a given client:
foreach (var k in list)
k.Naleznosci = dict[k.Id];
Now you have merged the values into the main list. Is this what you mean?
By the way, in your function that builds the dictionary, you make it accept a List<int>, but then all you do is call ToDictionary on it, which only requires IEnumerable<int>. So change the parameter type to that, and then you can call it:
var dict = GetNaleznosc(list.Select(k => k.Id));
This removes the call to ToList, which avoids making an unnecessary intermediate copy of the whole list of Ids. Probably won't make much difference in this case if you're hitting a database and then building up a large set of results in memory, but maybe worth bearing in mind for other uses of these operations.
Also, looking again at the helper function, there is no apparent advantage in building up the set of results in a dictionary for a list of ids, because each one is handled independently. You could simply put:
public decimal GetNaleznosc(int klientId)
{
return (from z in _zdarzenieRepository.List()
from c in z.Klient.Cennik
where z.TypZdarzenia == (int) TypyZdarzen.Sprzedaz && z.IdTowar == c.IdTowar && z.Sprzedaz.Data >= c.Od && (z.Sprzedaz.Data < c.Do || c.Do == null) && z.Klient.Id == klientId
select z.Ilosc*(z.Kwota > 0 ? z.Kwota : c.Cena)).Sum() ?? 0);
}
That is, provide a function that discovers just one value. Now you can directly build the right list:
public List<KlientViewModel> GetListOfKlientViewModel()
{
return _klientRepository.List().AsEnumerable().Select(k => new KlientViewModel
{
Id = k.Id,
Imie = k.Imie,
Nazwisko = k.Nazwisko,
Nazwa = k.Nazwa,
SposobPlatnosci = k.SposobPlatnosci,
Naleznosci = GetNaleznosc(k.Id)
}).ToList();
}

Linq To Nhibernate - Separated queries

I've got the following situation:
var totalRecords = (from entry in invalidAccEntryRepository
select entry).Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId).Count();
vs.
var totalRecords = (from entry in invalidAccEntryRepository
select entry);
if (CustomerAccountInfoFilterActive)
{
totalRecords.Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId);
}
totalRecordsCount = totalRecords.Count();
The first query works completely but the second query only executes the only
var totalRecords = (from entry in invalidAccEntryRepository
select entry);
and ignores the conditionally added where expression.
Anyone know what the problem could be? Do you need more info?
Thx in advance!
You aren't actually applying the where. In your if, use this instead:
totalRecords = totalRecords.Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId);

Resources