Add the query to have condition to use datediff function - c#

How to use datediff function in EntityFramework Core when I query the database entity.
I have the following query.
var delegates = await (from tn in _context.TrainingNotification
join cd in _context.CourseDelegate on
new { did = tn.CourseDelegateId, nid = (int?)tn.NotificationTypeId } equals
new { did = cd.CourseDelegateId, nid = cd.NotificationTypeId }
where !cd.Disabled
&& statusToFilter.Contains(cd.StatusType.StatusTypeCode)
&& cd.NotificationTypeId == 1
&& System.Data.Linq.DateDiffDay(DateTime.UtcNow.Date, tn.Created.Date) == daysToBeReminded
select new CourseDelegateUser
{
CourseDelegateId = cd.CourseDelegateId,
UserGuid = cd.UserGuid,
NotifiedUtc = tn.Created
}).ToListAsync();
I would like to get only those records whose created date is 5 days older.
How to achieve this?

The code you're using in the query is a Non-Sargable Query which is a low performance query.
Whenever a query has to perform a function on a value in a row, that value cannot use an index. However if you switch the function to the value you're comparing, then SQL can use an Index.
Instead of:
System.Data.Linq.DateDiffDay(DateTime.UtcNow.Date, tn.Created.Date) == daysToBeReminded
Use something like
var createdOn = DateTime.UtcNow.Date.AddDays(daysToBeReminded);
&& tn.Created.Date == createdOn;

Related

How do i add OR in between where using linq to entity query?

I wanted to search for multiple values from the same column using OR in linq. In SQL, it is something like this:
var query = "Select * from table where id = 1";
query += "OR where id = 2";
The id is from an array of ids so i pass the id to a variable and loop it. The number of id in the array is not fixed and depends on how many ids chosen by the user by checking on the checkbox in the table. Because if i do as below, it will return null because it somewhat inteprets my where query as AND. How do i change it so that it will get rows from all ids(using OR)?
Request request = db.Requests;
var selectedIdList = new List<string>(arrId);
if (arrId.Length > 0)
{
for (var item = 0; item <= selectedIdList.Count() - 1; item++)
{
var detailId = Convert.ToInt32(selectedIdList[item]);
request = request.Where(y => y.Id == detailId);
}
}
Simply use || for OR and && for AND inside Where
But I prefer :
request.Where(y => selectedIdList.Contains(y.Id));
If selectedIdList is an array of Strings :
request.Where(y => selectedIdList.Contains(y.Id.ToString());
You can use LinqKit. Linqkit provides things to create predicate dynamically
Just install linqKit using packageManager, And use predicateBuilder to build predicate
var predicate = PredicateBuilder.True<Patient>();
predicate=predicate.And(...)
OR
predicate=predicate.Or(...)
And then use predicate in ur where clause
This way you can create Or (dynamically) as you would in dynamic SQL
You can get more details from here
https://www.c-sharpcorner.com/UploadFile/c42694/dynamic-query-in-linq-using-predicate-builder/

Update IQueryable result before using as join in next query

I need to use Linq to Entity Framework to query a LOCATION table to get the record of the location code with the MAX effective date, then use that result as a join in the next query.
I BELIEVE I need to do convert before the IQueryable is used, because I have that last clause in the second query where I want to exclude records where the FLOOR code is in the excludedSchools list. That excludedSchools list will have the newLocationCode in it.
So, I need to update the values in the IQueryable result before I use it. Can I do this? Here is my code:
using (var db = new TheContext())
{
IQueryable<LocationTable> locatinWithMaxEffDate =
(from lc in db.LocationTable
where lc.EFF_STATUS == "A" && lc.EFFDT <= DateTime.Now
group lc by lc.LOCATION into g
select g.OrderByDescending(x => x.EFFDT).FirstOrDefault()
);
foreach (var location in locatinWithMaxEffDate.ToList())
{
string newLocationCode;
if(codeMappingDictionary.TryGetValue(location.FLOOR, out newLocationCode))
{
// how do I update locatinWithMaxEffDate FLOOR value
// with newLocationCode so it works in the query below?
location.FLOOR = newLocationCode;
}
}
var query =
(from fim in db.PS_PPS_FIM_EE_DATA
join mloc in locatinWithMaxEffDate on fim.LOCATION equals mloc.LOCATION
where
fim.EMPL_STATUS == PsPpsFimEeData.EmployeeStatusValues.Active
&& fim.AUTO_UPDATE == PsPpsFimEeData.AutoUpdateValues.Enabled
&& includeJobCodes.Contains(fim.JOBCODE)
&& !excludedSchools.Contains(mloc.FLOOR)
select new PpsAdministratorResult
{
SchoolId = mloc.FLOOR,
Login = fim.OPRID,
EmployeeId = fim.EMPLID,
}
With the code above, the locatinWithMaxEffDate does not have the updated FLOOR values. I can see why this is, but can't seem to fix it.
So far, I have tried introducing another list to ADD() the new location record to, then casting that as an IQueryable, but I get an error about primitive vs concrete types.
I decided to make things easier on myself. Since both sets of data are very small (fewer than 1000 records each) I call take the entire set of data as an annonymous type:
using (var db = new TheContext())
{
IQueryable<LocationTable> locatinWithMaxEffDate =
(from lc in db.LocationTable
where lc.EFF_STATUS == "A" && lc.EFFDT <= DateTime.Now
group lc by lc.LOCATION into g
select g.OrderByDescending(x => x.EFFDT).FirstOrDefault()
);
var query =
(from fim in db.PS_PPS_FIM_EE_DATA
join mloc in locatinWithMaxEffDate on fim.LOCATION equals mloc.LOCATION
where
fim.EMPL_STATUS == PsPpsFimEeData.EmployeeStatusValues.Active
&& fim.AUTO_UPDATE == PsPpsFimEeData.AutoUpdateValues.Enabled
&& includeJobCodes.Contains(fim.JOBCODE)
select new PpsAdministratorResult
{
SchoolId = mloc.FLOOR,
Login = fim.OPRID,
EmployeeId = fim.EMPLID,
}
}
Then, just work with the two objects:
List<PpsAdministratorResult> administratorList = new List<PpsAdministratorResult>();
foreach (var location in query.ToList())
{
string newLocationCode;
if(schoolCodeMappings.TryGetValue(location.SchoolId, out newLocationCode)) // && newLocationCode.Contains(location.LOCATION))
{
location.SchoolId = newLocationCode;
}
if( !excludedSchools.Contains(location.SchoolId) )
{
administratorList.Add(location);
}
}
Now, I have the list I want.

Proper use of StartWith and Contains in Entity Framework

I want to remove prefixes from StoreName field in Linq Linq to Entity query.
I have following query which gets list of all prefixes in table
Query1
var _prefix = context.Prefixes.Select(pre => pre.Prefix1);
I want to use this result in Query2
Query2
var objRetailer = from stores in context.RetailerStoredtls
join ret in context.RetailerContactdtls
on stores.RetailerID equals ret.RetailerID
join retreg in context.RetailerRegDates
on stores.RetailerID equals retreg.RetailerRegDateId
where (stores.IsDeleted == null || stores.IsDeleted == false)
&& (stores.CreatedDate.Value.Year == iYear || stores.ModifiedDate.Value.Year == iYear)
&& retreg.IsApproved== true
orderby stores.StoreName
select new
{
stores.StoreID,
Store = stores.StoreName,
Area = stores.StoreCity,
Zip = stores.StoreZip,
SellingCard = (storessellingcard.Contains(stores.RetailerID.Value) ? true : false)
StoreWithoutPrefix = stores.StoreName.StartsWith(<one of prefix retrieved from Query1> ? stores.StoreName : <stores.StoreName without prefix>
};
Unfortunately we have .StartWith() that take only string parameter not result of Query1, if I go with .Contains it will not check for whether it starts with or not, it just check whether string is present there. What should I do to accomplish this task?
Thanks.
You can use IndexOf, but probably you have problems with case sensitivity. So add a parameter CompareOptions.IgnoreCase

using linq to sql to specify where clause

I am using this method to get results to fill my grid but this method is also used to fill another grid which requires a where clause with two params and this one
only needs one. Even though i passed in null of the param that isn't used but still it is returning no results because of the where clause. Any advice of how i could
change this maybe use linq to sql where i call the method to specify the where clause instead of in the method getting data?
DocsForReview.DataSource = docLib.GetGrid(Guid.Empty, lib);
using (var dc = new DocMgmtDataContext())
{
var subs = (from doc in dc.Documents
join u in dc.Users on doc.OwnedByUserID equals u.ID
where doc.OwnedByUserID == usr && doc.LibraryID == lib
select new StudentDocuments
{
DocID = doc.ID,
Assignment = doc.Library.Name,
Submitted = doc.UploadDT,
Student = u.FullName
}).OrderByDescending(c => c.Submitted).AsEnumerable().ToList();
return subs;
}
For nullable types try this:
doc.LibraryID == (lib ?? doc.LibraryID)
In your case (a System.Guid) you can try this:
doc.LibraryID == (lib == Guid.Empty ? doc.LibraryID : lib)

LINQ Syntax for Current Revision

How can I write this SQL statement using C# and LINQ? I am quering an Oracle database and the table has multiple revisions of the records. Therefore, I want onyl the current revision of each record contained in the table.
The SQL looks like this:
select TP_ID, TP_TEXT, TP_DEFN_SAKEY
from TP_DEFN tp1
where tp1.TP_ACTIVE_FLAG = 'Y' and
tp1.FAMILY_ID = 1 and
tp1.TP_DEFN_REV_DTS = (select max(TP_DEFN_REV_DTS)
from TP_DEFN tp2
where tp2.family_id = tp1.family_id and tp2.tp_id = tp1.tp_id )
order by TP_ID
TP_DEFN_REV_DTS is the date time field that stores the current revision.
I am a beginner with LINQ and have been struggling to find an workable solution. Every time that I try grouping in the LINQ query I get an error
GroupBy is not supported
Try something like this:
var res =
from tp1 in TP_DEFN
where tp1.TP_ACTIVE_FLAG == "Y" &&
tp1.FAMILY_ID == 1 &&
tp1.TP_DEFN_REV_DTS == (from tp2 in TP_DEFN
where tp2.FAMILY_ID == tp1.FAMILY_ID &&
tp2.TP_ID == tp1.TP_ID
select tp2.TP_DEFN_REV_DTS).Max()
orderby tp1.TP_ID
select new
{
tp1.TP_ID,
tp1.TP_TEXT,
tp1.TP_DEFN_SAKEY
};
Off the top of my head, and not knowing which LINQ provider you're using...
var q = from tp1 in Context.TP_DEFN
where tp1.TP_ACTIVE_FLAG == "Y"
&& tp1.FAMILY_ID == 1
&& tp1.TP_DEFN_REV_DTS
== Context.TP_DEFN.Where(tp2 => tp2.FAMILY_ID == tp1.FAMILY_ID
&& tp2.TP_ID == tp1.TP_ID)
.Max(tp2 => tp2.TP_DEFN_REV_DTS)
orderby tp1.TP_ID
select new
{
tp1.TP_ID,
tp1.TP_TEXT,
tp1.TP_DEFN_SAKEY
};
If you're using entity framework or linq-to-sql, you can just pass the direct sql if you want (although that'll prevent change tracking, at least by default).
For EF, use ObjectContext.ExecuteStoreQuery: http://msdn.microsoft.com/en-us/library/dd487208.aspx
For L2S, use DataContext.ExecuteQuery: http://msdn.microsoft.com/en-us/library/system.data.linq.datacontext.executequery.aspx

Categories