Linq to entity with dynamically growing where clause - linq

I am trying to fetch data from an entity based on some criteria. The WHERE clause will have any number of 'OR' conditions. How can I acheive this?
var skill = skillset.split(";"); //array can have any number of items
var EmployeeList1 = EmployeeList
.Where(x => x.Primary1.ToUpper().Contains(skill[0])
|| x.Primary2.ToUpper().Contains(skill[0])
|| x.Primary1.ToUpper().Contains(skill[1])
|| x.Primary2.ToUpper().Contains(skill[1]))
.ToList();
return EmpMapper.Mapper.Map<List<EmployeeModel>>(EmployeeList1);
I need to build an expression for where clause with 'n' number of 'OR' conditions. I tried using predicate, but got exception(Index was outside the bounds of the array.).
var predicate = PredicateBuilder.New<ResourceEntity>(true);
for (int i = 0; i < skill.Count(); i++)
{
predicate= predicate.Or(p => p.Primary1.Contains(skill[i]));
}

You have to copy for variable into local variable:
var predicate = PredicateBuilder.New<ResourceEntity>(true);
for (int i = 0; i < skill.Length; i++)
{
var s = skill[i];
predicate = predicate.Or(p => p.Primary1.ToUpper().Contains(s));
predicate = predicate.Or(p => p.Primary2.ToUpper().Contains(s));
}

Related

Invalid Date whilst using Moment() and Linq

I am having a problem where I have a 12 month period but beginning from zero index and its causing me to have an invalid date. Below is a picture of both my date array and chart js. Basically, because the months are zero indexed, they are out by one
and the below is the Linq query I am using, if anyone can help me fix this that would be great
var solicitor = _db.Records
.Where(j => j.Requestor == "Solicitor" && EF.Functions.DateDiffMonth(j.Request_Date, DateTime.Now) == 0 && EF.Functions.DateDiffMonth(j.Request_Date, DateTime.Now) <= 12)
.GroupBy(g => new { g.Request_Date.Value.Year, g.Request_Date.Value.Month }).OrderBy(d => d.Key.Year).ThenBy(d => d.Key.Month)
.Select(group => new
{
Dates = group.Key,
Count = group.Count()
});
var solicitorCount = solicitor.Select(n => n.Count).ToArray();
var date = solicitor.Select(n => n.Dates).ToArray();
and the code inside my chart js to format as moment
let newArr = []
for (let i = 0; i < simpleData[0].date.length; i++) {
var calDate = moment(simpleData[0].date[i]).format('MMM YYYY');
console.log(calDate)
newArr.push(calDate)
}
You can change your code like this:
let newArr = []
for (let i = 0; i < simpleData[0].date.length; i++) {
data[i].month -= 1;
var calDate = moment(simpleData[0].date[i]).format('MMM YYYY');
console.log(calDate)
newArr.push(calDate)
}
newArr result:

EF Core performance issue when using dynamic query using Expressions in .Net

Requirement : Select list of records from table for members whose ID and First name matches with records.
The number of members in the request may vary as per the request:
I have written following code to generate dynamic query using expressions.
private Expression<Func<TmpOncMemberAuth, bool>> CreateQueryExpression(List<MemberRequest> memberRequests)
{
var type = typeof(TmpOncMemberAuth);
// member =>
var memberParam = Expression.Parameter(type, "member");
var requests = memberRequests;
Expression selectLeft = null;
Expression filterExpression = null;
foreach (var member in requests)
{
var comparison = BuildSubQuery(member, memberParam, type);
if (selectLeft == null)
{
selectLeft = comparison;
filterExpression = selectLeft;
continue;
}
filterExpression =
Expression.Or(filterExpression, comparison);
}
return Expression.Lambda<Func<TmpOncMemberAuth, bool>>
(filterExpression, memberParam);
}
private Expression BuildSubQuery(MemberRequest member, ParameterExpression memberParam, Type type)
{
// LHS
// member.MemberID
Expression leftMemberID = Expression.Property(memberParam, type.GetProperty("MemberId"));
Expression leftMemberFirstName = Expression.Property(memberParam, type.GetProperty("MemberFirstName"));
// RHS
Expression requestMemberID = Expression.Constant(member.MemberID);
Expression requestFirstName = Expression.Constant(member.FirstName);
// member.MemberID == requestMemberID
Expression compareID =
Expression.Equal(leftMemberID, requestMemberID);
Expression compareFName =
Expression.Equal(leftMemberFirstName, requestFirstName);
// condition for a member
Expression comparison = Expression.AndAlso(compareID, compareFName);
return comparison;
}
// query call in the main
var whereQuery = CreateQueryExpression(memberData);
var memberAuthData = await FindAllAsyncFromTemp(whereQuery);
This generate a SQL query in the below format, which take a lot time
SELECT [#].[CaseID] AS [CaseId], [#].[MemberID] AS [MemberId], [#].[MemberFirstName], [#].[MemberLastName], [#].[MemberDOB]
FROM [#ONCMemberAuth] AS [#]
WHERE ((CASE
WHEN (([#].[MemberID] = '12345') AND ([#].[MemberFirstName] = 'James') ) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END | CASE
WHEN (([#].[MemberID] = '6789') AND ([#].[MemberFirstName] = 'WILLERS') ) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END)
) = CAST(1 AS bit)
I need to create SQL query like below which executes faster than the above one
SELECT [#].[CaseID] AS [CaseId], [#].[MemberID] AS [MemberId], [#].[MemberFirstName], [#].[MemberLastName], [#].[MemberDOB]
FROM [#ONCMemberAuth] AS [#]
WHERE ((([#].[MemberID] = '1234') AND ([#].[MemberFirstName] = 'James')) OR (([#].[MemberID] = '56789') AND ([#].[MemberFirstName] = 'WILLERS') ) )

Where clause using Expression tree builder

I have to fetch data from database and filter data using the linq where clause.
My filter is an integer column and it contains value more than 1000.
What i am doing in the code is, breaking this huge array into chunk of 1000's of each and putting it in the where clause of a base query
int j = 0;
int batchsize = 1000;
while ((j * batchsize) < items.Count())
{
List<long> batch = items.Skip(j * batchsize)
.Take(batchsize).ToList();
prequery = prequery.Where(x => batch.Contains(x.Id));
j++;
}
the query which is getting generated in sql is below,
SELECT
x.name,
x.email
FROM
table x
WHERE
x.Id IN (1,2,3,...,1000) AND
x.Id IN (1001,1002,1003....,2000)
i want the query to be generated as below,
SELECT
x.name,
x.email
FROM
table x
WHERE
x.Id IN (1,2,3,...,1000) OR
x.Id IN (1001,1002,1003....,2000)
can i achieve this using expression tree builder and generate the query dynamically, if so please help in doing
you could use the "Concat" API:
int j = 0;
int batchsize = 1000;
IQueryable<YourType> finalQuery = null;
while ((j * batchsize) < items.Count())
{
List<long> batch = items.Skip(j * batchsize)
.Take(batchsize).ToList();
if (finalQuery == null) {
finalQuery = prequery.Where(x => batch.Contains(x.Id));
}
else
finalQuery = finalQuery.Concat (prequery.Where(x => batch.Contains(x.Id)));
j++;
}
This will logically get you what you want: basically you want an "OR" operation between batches. Concat is translated into an "UNION ALL" database call.
BUT ... I don't understand why are you doing this, after all you are grabbing all your data, chunks are not helping you because in the end there will be only one statement executed.

query cannot be enumerated more than once

I want to do the following
var totalNoOfRows = result.First().TotalNumberOfCount;
And finally do something like that
bookssList.AddRange(retResult.Select(r => r.ToBook()));
where ToBook is extended method
but I always get The result of a query cannot be enumerated more than once.
if (result != null)
{
var totalNoOfRows = result.First().TotalNumberOfCount;
pagingContext.ItemsTotal = totalNoOfRows != null ? int.Parse(totalNoOfRows.ToString()) : 0;
var retResult = result.ToList();
// pagingContext.ItemsTotal = totalcount.Value != null ? int.Parse(totalcount.Value.ToString()) : 0;
bookssList.AddRange(retResult.Select(r => r.ToBook()));
}
Hard to guess what are you doing, and how these snippets relate to each other, but if you can enumerate a collection only once, then call ToArray first:
var resultCopy = result.ToArray();
//... any number of operations on resultCopy
Note that calling First also counts as enumerating. So you need to enumerate and copy the collection even before this.
Try changing the code to this, so you only enumerate result once:
var retResult = result.ToList();
var totalNoOfRows = retResult.First().TotalNumberOfCount; //You are now using LINQ on the list, not the query!
pagingContext.ItemsTotal = totalNoOfRows != null ? int.Parse(totalNoOfRows.ToString()) : 0;
// pagingContext.ItemsTotal = totalcount.Value != null ? int.Parse(totalcount.Value.ToString()) : 0;
Logger.LogInfo("Search Payments GetPaymentsWithCount stored procedure result not null and count=" + totalcount);
bookssList.AddRange(retResult.Select(r => r.ToBook()));

Replace certain cell values in a column

Disclaimer: I am Newb. I understand scripting a little, but writing it is a pain for me, mostly with loops and arrays, hence the following.
I am attempting to pull all of the data from a specific column (in this case H [8]), check each cell's value in that column and if it is a y, change it to Yes; if it's n, change it to No; if it's empty, leave it alone and move onto the next cell.
Here's what I have so far. As usual, I believe I'm pretty close, but I can't set the value of the active cell and I can't see where I'm messing it up. At one point I actually changed ever value to Yes in the column (so thankful for undo in these cases).
Example of Sheet:
..... COL-H
r1... [service] <-- header
r2... y
r3... y
r4... n
r5... _ <-- empty
r6... y
Intent: Change all y's to Yes and all n's to No (skip blank cells).
What I've tried so far:
Function attempt 1
function Thing1() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("mySheet");
var lrow = ss.getLastRow();
var rng = ss.getRange(2, 8, lrow - 1, 1);
var data = rng.getValues();
for (var i=0; i < data.length; i++) {
if (data[i][0] == "y") {
data[i][0] == "Yes";
}
}
}
Function attempt 2
function Thing2() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("mySheet");
var lrow = ss.getLastRow();
var rng = ss.getRange(2, 8, lrow - 1, 1);
var data = rng.getValues();
for (var i=0; i < data.length; i++) {
if (data[i][0] == "n") {
data.setValue("No");
} else if (data[i][0] == "y") {
data.setValue("Yes");
}
}
}
Usage:
Once I'm done here, I want to modify the function so that I can target any column and change one value to another (I already have a method for that, but I need to be able to set the value). It would be like so: =replace(sheet, col, orig_value, new_value). I will post it as well below.
Thanks in advance for the help.
Completed Code for searching and replacing within a column
function replace(sheet, col, origV1, newV1, origV2, newV2) {
// What is the name of the sheet and numeric value of the column you want to search?
var sheet = Browser.inputBox('Enter the target sheet name:');
var col = Browser.inputBox('Enter the numeric value of the column you\'re searching thru');
// Add old and new targets to change (Instance 1):
var origV1 = Browser.inputBox('[Instance 1:] What old value do you want to replace?');
var newV1 = Browser.inputBox('[Instance 1:] What new value is replacing the old?');
// Optional - Add old and new targets to change (Instance 2):
var origV2 = Browser.inputBox('[Instance 2:] What old value do you want to replace?');
var newV2 = Browser.inputBox('[Instance 2:] What new value is replacing the old?');
// Code to search and replace data within the column
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet);
var lrow = ss.getLastRow();
var rng = ss.getRange(2, col, lrow - 1, 1);
var data = rng.getValues();
for (var i=0; i < data.length; i++) {
if (data[i][0] == origV1) {
data[i][0] = newV1;
} else if (data[i][0] == origV2) {
data[i][0] = newV2;
}
}
rng.setValues(data);
}
Hope this helps someone out there. Thanks Again #ScampMichael!
The array named data was created from the values in the range and is independent of the spreadsheet after it is created so changing an element in the array does not affect the spreadsheet. You must modify the array and then put the whole array back where it came from.
for (var i=0; i < data.length; i++) {
if (data[i][0] == "n") {
data[i][0] = "No";
} else if (data[i][0] == "y") {
data[i][0] = "Yes";
}
}
rng.setValues(data); // replace old data with new
}

Resources