Linq query across 2 datasets while using String.Split - c#

I am trying to check if an entity exists using certain filters. This is what I started with
bool jff = (from fm in dc.FamilyMembers
from f in dc.FamilyInfos
where fm.Family_ID == f.Family_ID && (fm.Last_Name == item.LastName && fm.Birthdate == item.DOB && f.Address1.Split(' ')[0].Contains(addNumber))
select new { fm, f }).Any();
Then I used AsEnumberable
bool jff = (from fm in dc.FamilyMembers.AsEnumberable()
from f in dc.FamilyInfos.AsEnumberable()
where fm.Family_ID == f.Family_ID && (fm.Last_Name == item.LastName && fm.Birthdate == item.DOB && f.Address1.Split(' ')[0].Contains(addNumber))
select new { fm, f }).Any();
It took 3 mins, so I'm guessing this isn't the best way. Can anyone give any suggestions?

Well best way is to do this in the database instead of loading all into memory. Howeverer, a join and a pre-filter should be much more efficient:
var relevantFamilies = dc.FamilyMembers
.Where(fm => fm.Last_Name == item.LastName && fm.Birthdate == item.DOB);
var relevantFamilyInfo =
from fm in relevantFamilies
join fi in dc.FamilyInfos on fm.Family_ID equals fi.Family_ID
select fi;
bool result = relevantFamilyInfo.AsEnumerable() // because you store multiple informations in Address1 you need to execute part of the query in memory, normalize your DB
.Any(info => info.Address1.Split(' ')[0].Contains(addNumber));

EF Core has not translation for Split, but you can emulate first element retrieval:
bool jff = (
from fm in dc.FamilyMembers
from f in dc.FamilyInfos
where fm.Family_ID == f.Family_ID && fm.Last_Name == item.LastName && fm.Birthdate == item.DOB
&& f.Address1.Substring(0, f.Address1.IndexOf(" ")).Contains(addNumber)
select new { fm, f }
).Any();

Related

How to split string in c# linq?

I have this
from d in db.v_Report_CompanySearches
orderby d.InquiryLogID descending
where (mPersonName == null || d.AccountName.ToLower() == mPersonName || d.PersonName.ToLower() == mPersonName) &&
(mCompanyName == null || TagsContain(d.CompanySearchTerm, mCompanyName)) &&
d.CreateDT >= mFrom && d.CreateDT <= mTo
select (d);
and
private bool TagsContain(string terms, string val)
{
string[] tags = terms.ToLower().Split(';');
return tags.Contains(val.ToLower());
}
but it crashes with not supported error. I think it's because I'm using a custom function TagsContain. How can I do that function in linq without custom stuff?
Thanks
Id TagsContain isn't supported by EF and have an underlying SQL function, it will crash. That's exactly what is happening here.
This however, should work:
from d in db.v_Report_CompanySearches
orderby d.InquiryLogID descending
where (mPersonName == null || d.AccountName.ToLower() == mPersonName || d.PersonName.ToLower() == mPersonName) &&
(mCompanyName == null || d.CompanySearchTerm.Contains(mCompanyName)) &&
d.CreateDT >= mFrom && d.CreateDT <= mTo
select (d);
Provider not able convert your custom function the sql. And I afraid split is one of the functions which not supported for generating sql.
You can use it without .Split
var query =
db.v_Report_CompanySearches
.Where(report => report.CreateDT >= from)
.Where(report => report.CreateDT <= to);
if (String.IsNullOrEmpty(personName) == false)
{
query = query.Where(report => report.AccountName.ToLower() == personName ||
report.PersonName.ToLower() == personName);
}
if (String.IsNullOrEmpty(companyName) == false)
{
query = query.Where(report => report.CompanySearchTerm.StartsWith($"{companyName};") ||
report.CompanySearchTerm.Contains($";{companyName};")) ||
report.CompanySearchTerm.EndsWith($";{companyName}"))
}
var result = query.OrderByDescending(report => report.InquiryLogID).ToList();
What Fabio said is right. Split function of c# can not be converted into SQL query. So, you have one way here
Get all the values from DB into C# List object and then apply the split filter over it.
var myListObject = (from d in db.v_Report_CompanySearches
orderby d.InquiryLogID descending
where (mPersonName == null || d.AccountName.ToLower() == mPersonName || d.PersonName.ToLower() == mPersonName) &&
d.CreateDT >= mFrom && d.CreateDT <= mTo
select (d)).ToList();
Then
var afterFilterObject = myListObject.Where(d => (d.mCompanyName == null || TagsContain(d.CompanySearchTerm, mCompanyName))).ToList();
Method to be called
private bool TagsContain(string terms, string val)
{
string[] tags = terms.ToLower().Split(';');
return tags.Contains(val.ToLower());
}

Entity Framework method group Include does not work

I have some troubles with Loading Related Entities with a method group in EF.
In simple queries the Loading of Related Entities works ok with Include.
For example:
var result =
Repository.Query<TimeState>(x => x.Accepted == 0 && x.ProjectID != null && myTeam.Contains(x.EmployeeID))
.Include(typeof(Project).Name)
.Include(typeof(Employee).Name)
.Include(typeof(EmployeeDetails).Name)
.OrderByDescending(x => x.SubmitedDate);
Works perfect, and Loads the Project and the Employee
but in the next query does not load the Project and the Employee
var result2 = from item in Repository.Query<TimeState>(x => x.Accepted == 0 && x.ProjectID != null)
.Include(typeof(Project).Name)
.Include(typeof(Employee).Name)
.Include(typeof(EmployeeDetails).Name)
let projectId = (int)item.ProjectID
let isA = projectsIds.Contains(projectId) && item.Employee.EmployeeDetails.SuperiorID == id
let isB = item.Project.ManagerID == id && employeesTeam.Contains(item.EmployeeID)
where isA || isB
orderby item.SubmitedDate descending
select item;
I tried to do such a change: select new { item, item.Employee, item.Project };
var result3 = from item in Repository.Query<TimeState>(x => x.Accepted == 0 && x.ProjectID != null)
.Include(typeof(Project).Name)
.Include(typeof(Employee).Name)
.Include(typeof(EmployeeDetails).Name)
let projectId = (int)item.ProjectID
let isA = projectsIds.Contains(projectId) && item.Employee.EmployeeDetails.SuperiorID == id
let isB = item.Project.ManagerID == id && employeesTeam.Contains(item.EmployeeID)
where isA || isB
orderby item.SubmitedDate descending
select new { item, item.Employee, item.Project };
After that, result3[0].Employee has a value, the same for result3[0].Project (or any other item from that collection).
The problem is that I don't need the Employee and the Project as separate properties in this dynamic object result3.
How is possible to have Employee and Project in the method which returns result2 ? :)
I rarely use query syntax, and I've never run into someone using .Include(typeof(..).Name) syntax so try the following:
var result2 = (from item in Repository.Query<TimeState>(x => x.Accepted == 0 && x.ProjectID != null)
let projectId = (int)item.ProjectID
let isA = projectsIds.Contains(projectId) && item.Employee.EmployeeDetails.SuperiorID == id
let isB = item.Project.ManagerID == id && employeesTeam.Contains(item.EmployeeID)
where isA || isB
orderby item.SubmitedDate descending
select item)
.Include(i=>i.Projects)
.Include(i=>i.Employees)
.Include(i=>i.EmployeeDetails);
You may need to include using System.Data.Entity; as well for this to work.

Entity framework LINQ speed converting SQL data into C# objects

I have a fairly complex query written in LINQ which queries my database. I have made sure that I am only pulling back the relevant columns from each entity, so the query is as slim as it can be, and therefore the object which LINQ populates does not contain any unnecessary columns either.
If I run the LINQ query's resulting SQL against the DB directly, the SQL runs in about 4 seconds. However, doing this from my LINQ query takes about 25 seconds. The majority of this 25 seconds is taken up by the returned DB data being written into objects.
Are there any useful tricks which will help LINQ/Entity Framework out when performing this part of the operation?
Edit:
The long delay occurs when I call the ToList() method in the query below:
var q1 = from u in etc.Users
where (u.flags & (int)UserFlags.Student) == (int)UserFlags.Student
&& (ariStudents.Contains(u.id) || ariStudents.Count == 0)
&& (from ua in etc.UserAssociations where ua.datasetId == datasetId && ua.userId == u.id && ua.type == (int)UserAssocTypes.EnrolActive select ua).Any()
orderby u.id
select new ElightsRaw2
{
Student = new ElrStudent{StudentId = u.id},
StudentData = (
from sd in etc.StudentDatas
where sd.userId == u.id
&& sd.datasetId == datasetId
select new ElrStudentData { attP = sd.attP, attA = sd.attA, attL = sd.attL }
).FirstOrDefault(),
ElightOverall = (
from els in etc.eLightsStudents
where els.datasetId == datasetId
&& els.userId == u.id
select els
).FirstOrDefault(),
Groups = (
// get all courses and groups for user
from c in etc.Cours
join g in etc.Groups on c.id equals g.courseId
join ua in etc.UserAssociations on g.id equals ua.fkId
where ua.datasetId == datasetId
&& ua.userId == u.id
&& ua.type == (int)UserAssocTypes.EnrolActive
&& (ua.flags & (int)UserAssociationFlags.AssociationDeleted) == 0
&& (c.flags & (int)CourseFlags.Deleted) == 0
select new ElrGroupHolder
{
CourseName = c.name,
GroupName = g.name,
Breakdown = new ElrGroupHolderBreakdown
{
UnitsBelowScoreThresh1 = (
from uus in etc.UserUnitScores
join un in etc.Units on uus.unitId equals un.id
join cu in etc.CourseUnits on un.id equals cu.unitId
where uus.userId == u.id
&& (un.flags & (int)UnitFlags.Deleted) == 0
&& (cu.flags & (int)CourseUnitFlags.NotStarted) == 0
&& cu.courseId == c.id
&& (uus.performance > -1 && uus.performance <= amberThresh)
&& !(from exc in etc.UserAssociations where exc.userId == u.id && exc.fkId == un.id && exc.type == (int)UserAssocTypes.ExcludedUnit select exc).Any() // not excluded from unit
select uus
).Count(),
UnitsBelowScoreThresh2 = (
from uus in etc.UserUnitScores
join un in etc.Units on uus.unitId equals un.id
join cu in etc.CourseUnits on un.id equals cu.unitId
where uus.userId == u.id
&& (un.flags & (int)UnitFlags.Deleted) == 0
&& (cu.flags & (int)CourseUnitFlags.NotStarted) == 0
&& cu.courseId == c.id
&& (uus.performance > -1 && uus.performance <= redThresh)
&& !(from exc in etc.UserAssociations where exc.userId == u.id && exc.fkId == un.id && exc.type == (int)UserAssocTypes.ExcludedUnit select exc).Any() // not excluded from unit
select uus
).Count(),
CfcCount = (
from cfc in etc.CFCs
where cfc.datasetId == datasetId
&& cfc.studentId == u.id
&& cfc.dt > dCfcCutoff
&& cfc.type == (int)CfcTypes.Concern
&& (cfc.flags & (int)CfcFlags.Deleted) == 0
&& (
// only include attendance and behaviour CFCs
(cfc.flags & (int)CfcFlags.Attendance) == (int)CfcFlags.Attendance
|| (cfc.flags & (int)CfcFlags.Behaviour) == (int)CfcFlags.Behaviour
)
select cfc
).Count(),
SrsScores = (
from srs in etc.SRScores
join sr in etc.SubReviews on srs.srId equals sr.id
where sr.datasetId == datasetId
&& (sr.flags & (int)SrFlags.Deleted) == 0
&& (srs.flags & (int)SrsFlags.Deleted) == 0
&& sr.dt > dCfcCutoff
&& sr.userId == u.id
&& sr.courseId == c.id
select new ElrSrScore
{
attainment = srs.attainment,
attitude = srs.attitude,
motivation = srs.motivation,
studyskill = srs.studyskill
}
).ToList(),
ElightEnrolment = (
from ele in etc.eLightsEnrolments
where ele.datasetId == datasetId
&& ele.groupId == g.id
&& ele.userId == u.id
select ele
).FirstOrDefault(),
},
CourseAttendance = (
from a in etc.Attendances
where a.studentId == u.id
&& a.courseId == c.id
&& a.weekNumberId == null
&& a.datasetId == datasetId
select a
).FirstOrDefault()
}
).ToList(),
};
return q1.ToList();
Yes! I ran into something similar myself not to long ago. What I came up with is using the AsParallel() function within LINQ ... however this comes with a few caveats.
You will be running things in parallel - obvious but if your trying to do things in a non thread safe manner there could be issues
This will only be useful in certain cases - the way I got the most use out of it was when I was converting a lot of database rows into C# objects and doing it repetitively ... think foreach,for,while loops that don't have any decision logic in them but just a straight database row to C# class kind of conversion
It really only makes sense for "large" amounts of data - You're going to have to play around with this and see what the timing difference is but if you are just converting a handful of rows, the overhead for AsParallel() will actually cost you more time, not save you any.
Here is some more reading on AsParallel(), hope this helps!
https://msdn.microsoft.com/en-us/library/vstudio/dd413237%28v=vs.100%29.aspx - AsParallel Method
https://msdn.microsoft.com/en-us/library/dd997425%28v=vs.110%29.aspx - Intro to parallel queries
http://www.dotnetperls.com/asparallel - Good basic walkthrough of AsParallel

asp.net mvc LINQ datetime problem

string NewsFillter = string.Empty;
List<string> PublishDatePostMeta = (from post in postrepository.GetAllPosts()
join pstmt in postrepository.GetAllPostMetas()
on post.int_PostId equals pstmt.int_PostId
where (post.int_PostTypeId == 4 && post.int_PostStatusId == 2 && post.int_OrganizationId == layoutrep.GetSidebarDetailById(SidebarDetailsId).int_OrganizationId) && pstmt.vcr_MetaKey=="Publish Date"
select pstmt.vcr_MetaValue).ToList();
int DatesCount = PublishDatePostMeta.Count();
foreach (string PublishDate in PublishDatePostMeta)
{
if (PublishDate != "")
{
NewsFillter += System.DateTime.Now + ">=" + Convert.ToDateTime(PublishDate);
}
}
var postsidebar = from post in postrepository.GetAllPosts()
join pstmt in postrepository.GetAllPostMetas()
on post.int_PostId equals pstmt.int_PostId
where (post.int_PostTypeId == 4 && post.int_PostStatusId == 2 && post.int_OrganizationId == layoutrep.GetSidebarDetailById(SidebarDetailsId).int_OrganizationId)
&& (pstmt.vcr_MetaKey.Contains(filter) && pstmt.vcr_MetaValue.Contains("true"))
select post;
1st question .The thing is that how NewsFillter would be accomdated in the postsidebar query in the pstmt object after true ( i would be putting it in contains,equals join or what) .
2nd question . is there any way that a chunk (between &&s) return enumerable and i can get away with this. at this moment it is not allowing that
I haven't udnerstood you properly, but if you want to apply multiple filters, here is my solution:
//Book is a table in the database
List<Expression<Func<Book, bool>>> filters = new List<Expression<Func<Book, bool>>>();
IQueryable<Book> query = dc.Books;
filters.Add(b => b.BookId == long.Parse(id));
//apply all filters
foreach (var f in filters)
query = query.Where(f);
Your questions:
This question requires an example of input and output. Try something like this:
|| pstmt.vcr_MetaKey=="Publish Date" && (
pstmt.vcr_MetaValue == "" || DateTime.Parse(pstmt.vcr_MetaValue) < DateTime.Now)
There is method AsEnumerable, if you mean what I think.

Dynamic LINQ Multiple Where Clause

Still really struggling with this and appear to be going round in circles.
I have the following code that is driving me nuts. It should populate a list of items to be used in an autocomplete text box:
public string[] GetAutoComplete(string prefixText, int count)
{
string memberid = HttpContext.Current.Session["MemberID"].ToString();
string locationid = HttpContext.Current.Session["LocationID"].ToString();
string inhouse = HttpContext.Current.Session["Inhouse"].ToString();
string supplier = HttpContext.Current.Session["Supplier"].ToString();
string groupw = HttpContext.Current.Session["Group"].ToString();
string external = HttpContext.Current.Session["External"].ToString();
MyEnts autocomplete = new MyEnts();
var r = from p in autocomplete.tblAutoCompletes
where p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText)
select p.ACItem;
if (inhouse == "Inhouse")
r = r.Where(p => p == inhouse);
if (supplier == "Supplier")
r = r.Where(p => p == supplier);
if (groupw == "Group")
r = r.Where(p => p == groupw);
if (external == "External")
r = r.Where(p => p == external);
r.OrderBy(p => p);
return r.ToArray();
What I am trying to retrieve with the dynamic where clause along the lines of the following.
Should inhouse = "Inhouse", then the list of items should include the word "Inhouse". If inhouse != "Inhouse", the word "Inhouse" should be excluded from the list.
This same logic should then be applied across the different where clauses i.e. Supplier, Group, External.
I genuinely have tried lots of different methods but I cannot for the life of me get the thing to work and it's frustrating me somewhat.
If anyone can suggest a way of doing this, you will either get a big kiss or a big frosty beer should our paths ever cross.
Not exactly sure about your problem here but if you want to exclude then shouldn't the code be something like
if (inhouse == "Inhouse")
r = r.Where(p => p == inhouse);
else
r = r.Where(p => p != inhouse);
Oh! if you want just exclusion then the code should be something like
if (inhouse != "Inhouse")
r = r.Where(p => p != inhouse);
If the set of values to include/exclude is known at compile-time (as appears to be the case in your example), I think this can be managed with one query:
string memberid = HttpContext.Current.Session["MemberID"].ToString();
string inhouse = HttpContext.Current.Session["Inhouse"].ToString();
string supplier = HttpContext.Current.Session["Supplier"].ToString();
bool includeInHouse = (inhouse == "Inhouse");
bool includeSupplier = (supplier == "Supplier");
MyEnts autocomplete = new MyEnts();
var r = from p in autocomplete.tblAutoCompletes
where (p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText))
&& (includeInHouse || (p.ACItem != "InHouse"))
&& (includeSupplier || (p.ACItem != "Supplier"))
select p.ACItem;
r.OrderBy(p => p.ACItem);
return r.ToArray();
I've eliminated a couple cases for brevity.
Wouldn't each of your Where clauses just need to contain a Contains criteria and some Not Contains?
if (inhouse == "Inhouse")
r = r.Where(p => p.Contains(inhouse) && !p.Contains("Supplier") && !p.Contains("Group") && !p.Contains("External"));
Sorted.
var r = from p in autocomplete.tblAutoCompletes
where p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText)
select p.ACItem;
if (inhouse != "Inhouse")
r = r.Where(p => p != "Inhouse");
if (supplier != "Supplier")
r = r.Where(p => p != "Supplier");
if (groupw != "Group")
r = r.Where(p => p != "Group");
if (external != "External")
r = r.Where(p => p != "External");
r = r.OrderBy(p => p);
return r.ToArray();
I had to set the exception in quotation marks as the session vlaue was inappropriate and wouldn't have picked out anything from the list.
Thanks to all those contributing and helping me out.

Categories

Resources