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.
Related
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();
i don't know how to handle this in LINQ
simply i have a searchKey in which i am passing user enter data and it return with rows. but if i am not passing any searchkey it not given any data. i dont want to add contains if searchkey is empty :(
var AppointmentList = (from app in Con.ios_Appointment
where (app.IS_DELETED == false && app.CLINICIANID == appReq.id
&& app.FNAME.Contains(appReq.searchKey.Trim()) || app.LNAME.Contains(appReq.searchKey.Trim()) || app.ADDRESS.Contains(appReq.searchKey.Trim())
)
orderby app.DATE descending
select new
{
app.ID,
app.FNAME,
app.LNAME,
app.DATE,
app.LONGITUDE,
app.LATITUDE,
app.ADDRESS,
app.STATUS,
app.START_TIME
}).Skip(skipRecord).Take(Convert.ToInt32(record)).ToList();
I suggest you use method syntax to easily build the query up programatically:
var query = Con.ios_Appointment.Where(app => !app.IS_DELETED && app.CLINICIANID == appReq.id);
var search = appReq.searchKey.Trim();
if (search != "")
{
query = query.Where(app => app.FNAME.Contains(search) ||
app.LNAME.Contains(search) ||
app.ADDRESS.Contains(search));
}
var appointments = query
.OrderByDescending(app => app.DATE)
.Select(app => new
{
app.ID,
app.FNAME,
app.LNAME,
app.DATE,
app.LONGITUDE,
app.LATITUDE,
app.ADDRESS,
app.STATUS,
app.START_TIME
})
.Skip(skipRecord)
.Take(Convert.ToInt32(record))
.ToList();
You need to use string.IsNullOrWhiteSpace method:
where (app.IS_DELETED == false &&
app.CLINICIANID == appReq.id &&
(string.IsNullOrWhiteSpace(appReq.searchKey) ||
app.FNAME.Contains(appReq.searchKey.is Trim()) || ...
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());
}
Caveat: I know some parts of this code are bad, but it is what it is for now. I just want it to run properly. I fully intend to refactor later. I just need a working app right now.
The initial linq query grabs several fields of data, but more data must be added per item in the resultset. So, we have the foreach below. It grabs data and updates each row.
It overwrites everything to what I'm thinking is probably the last iteration of the foreach. Why? How do I keep it from overwriting?
Keep in mind that the working variable just meabns a period id. I want to get previous or future periods, and subtracting or adding to this allows this.
public List<intranetGS.Forecast> getForecast(int branchId) {
//user role protection here
intraDataContext q = new intraDataContext();
//this grabs the initial data
var basefc = (from f in q.fc_items
where f.color_option == false
select new intranetGS.Forecast {
itemId = f.item_id,
item = f.item_number,
itemDesc = f.description,
itemSuffix = f.item_suffix,
itemPrefix = f.item_prefix,
designation = f.designation
});
//now we filter
switch (getDesignation(branchId)) {
case 1:
basefc = basefc.Where(n => n.designation != 3);
basefc = basefc.Where(n => n.designation != 6);
break;
case 2:
basefc = basefc.Where(n => n.designation > 3);
break;
case 3:
basefc = basefc.Where(n => n.designation != 2);
basefc = basefc.Where(n => n.designation != 6);
break;
}
var current = Convert.ToInt32(DateTime.Now.Month);
var working = 0;
var year = Convert.ToInt32(DateTime.Now.Year);
List<intranetGS.Forecast> res = new List<intranetGS.Forecast>();
foreach (var f in basefc) {
working = getPeriod(current + "/" + (year - 1)); //starting with last year;
var ly = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(ly, null)) {
f.lastYearForecast = ly.forecast;
f.lastYearReceipt = ly.receipt;
}
working = getPeriod(current + "/" + year) - 2; //two months ago
var m2 = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(m2, null)) {
f.twoMosForecast = m2.forecast;
f.twoMosReceipts = m2.receipt;
f.twoMosUsage = m2.usage_lb;
}
working = getPeriod(current + "/" + year) - 1; //one month ago
var m1 = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(m1, null)) {
f.oneMosForecast = m1.forecast;
f.oneMosReceipts = m1.receipt;
f.oneMosUsage = m1.usage_lb;
}
working = getPeriod(current + "/" + year); //current month
var m = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(m, null)) {
f.currentMosForecast = m.forecast;
f.currentMosReceipts = m.receipt;
f.currentMosusage = m.usage_lb;
}
working = getPeriod(current + "/" + year) + 1; //one month from now
var mnext1 = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(mnext1, null)) {
f.plusOneForecast = mnext1.forecast;
f.plusOneForecastId = mnext1.forcast_id;
}
working = getPeriod(current + "/" + year) + 2; //two months from now
var mnext2 = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(mnext2, null)) {
f.plusTwoForecast = mnext2.forecast;
f.plusTwoForecastId = mnext2.forcast_id;
}
} //this is insanely and extremely cumbersome; refactor later.
return basefc;
}
UPDATE: It wasn't a list, it needed to be a list to avoid the overwrite.
The issue is that there is a delayed execution which occurs in linq as the user is building the query and internally it is building an expression tree where new expressions can be added. Once the query factors are settled upon during an execution, such as an enumerable target in a for loop or via .ToList() that list is fluid still. Since the code was simply adding more expressions and not filtering it out into a new list, the query just grew.
The question is when working on existing code, did the developer want to keep building the expression tree for performance or did they intend to make the items concrete at each step along the process?.
You may be fixing an issue by making the initial list concrete but could be introducing a logic bug going forward. Keep that in mind.
I have Table HR_Travel(TravelID, TravelCode....) and HR_TravelDocuments(TravelDocID, TravelID, DocUrl)
FromDate = FromDate.AddDays(1);
ToDate = ToDate.AddDays(1);
List<dynamic> Lst = new List<dynamic>();
var queryTravelDetails = from t in db.HR_TravelDetails
where ((t.StatusDate >= FromDate && t.StatusDate <= ToDate)
&& (t.EmpID == EmpID || EmpID == 0) && (t.TravelStatus == TravelStatus || TravelStatus == "All"))
orderby t.StatusDate descending
select new
{
TravelID = t.TravelID,
TravelSubID = db.HR_TravelDetails.Where(i => i.TravelID == 0).FirstOrDefault().TravelID == null ? 0 : db.HR_TravelDetails.Where(i => i.TravelID == 0).FirstOrDefault().TravelID,
t.TravelCode,
t.EmpID,
EmpName = db.EE_Employee.Where(i => i.EmpID == t.EmpID).FirstOrDefault().EmpName,
t.CellNo,
t.BoardingForm,
t.DestinationTO,
t.JournyDate,
t.Purpose,
t.Organization,
t.TravelStatus,
DocUrl = DocUrl = string.Join(",",( db.HR_TravelDocuments.Where(i => i.TravelID == t.TravelID && i.TravelSubID == 0).Select(i => i.DocUrl).ToList()))
};
foreach (var element in queryTravelDetails)
{
Lst.Add(element);
}
Gives the following error:
LINQ to Entities does not recognize the method 'System.String Join[String](System.String, System.Collections.Generic.IEnumerable`1[System.String])' method, and this method cannot be translated into a store expression.
The Join() method can't be used in LINQ expressions, because it cannot translate from CLR to T-SQL. Another example is that you can't use:
var itemCount = db.Table.Count(p => p.Something == SomeFunction(someVariable));
You should move the method call outside the LINQ statement:
var anotherVariable = SomeFunction(someVariable);
var itemCount = db.Table.Count(p => p.Something == anotherVariable);
I hope I explained in a good way.
EDIT: As seen in the comments before, you can also use ToArray() and when the data is loaded locally you can use functions in statements freely.