Comma separated List in linq select - c#

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.

Related

LINQ with Contains return zero rows if i am passing empty string

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

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

Linq - Dynamic Condition

I have the following query :-
I want to add one more condition which is dynamic, so if user passes DATEOFBIRTH it should be e.DateOfBirth <= date.
var data = ctx.Employee.Where(e => e.Id == Id
&& e.Category == Category
&& e.DateOfJoining <= date)
.Select(e => e)
.ToList();
How to condition dynamically?
You can use reflection to solve this problem but there is another idea that may helps you:
var criteria = new Dictionary<string, Func<Employee, bool>>();
var date = DateTime.Now; //or any other value
//Initialize your criterias
criteria.Add("DATEOFBIRTH", e => e.DateOfBirth <= date);
criteria.Add("DateOfJoining", e => e.DateOfJoining <= date);
var selectedValue = "DATEOFBIRTH";
var data = ctx.Employee.Where(e => e.Id == id &&
e.Category == Category &&
criteria[selectedValue](e)).ToList();
So if you change the selectedValue the output will be based on corresponding criteria you are looking for.
From your comment:
If the DateOfBirth is choosen, there where condition should be appended
by one more condition e.DateOfBirth <= date.. if user chooses
DateOfAnniversary then it should be e.DateOfAnniversary <= date
Then you could use:
var data = ctx.Employee
.Where(e => e.Id == Id && e.Category == Category && e.DateOfJoining <= date);
Now, assuming that filterbyDateOfBirth and filterbyDateOfAnniversary are bools:
if(filterbyDateOfBirth)
data = data.Where(e => e.DateOfBirth <= date);
if(filterbyDateOfAnniversary)
data = data.Where(e => e.DateOfAnniversary <= date);
var list = data.ToList();
Due to LINQ's deferred execution the database is queried just once at ToList.
Sounds like you're trying to do the following:
var employees = ctx.Employee.Where(e => e.Id == Id
&& e.Category == Category
&& e.DateOfJoining <= date);
if (!string.IsNullOrWhiteSpace(DATEOFBIRTH))
{
employees = employees.Where(e => e.DateOfBirth <= DATEOFBIRTH);
}
var data = employees.ToList();
You could also do the following, which is more concise, but since it looks like you are querying a database here, I would prefer the above approach since it doesn't include anything unnecessary in the query.
var data = ctx.Employee.Where(e => e.Id == Id &&
e.Category == Category &&
e.DateOfJoining <= date &&
(string.IsNullOrWhiteSpace(DATEOFBIRTH) ||
e.DateOfBirth <= DATEOFBIRTH))
.ToList();

LINQ to Entities does not recognize the method

This is my Code where I am fetching data.
var list = (from u in _dbContext.Users
where u.IsActive
&& u.IsVisible
&& u.IsPuller.HasValue
&& u.IsPuller.Value
select new PartsPullerUsers
{
AvatarCroppedAbsolutePath = u.AvatarCroppedAbsolutePath,
Bio = u.Bio,
CreateDateTime = u.CreationDate,
Id = u.Id,
ModifieDateTime = u.LastModificationDate,
ReviewCount = u.ReviewsReceived.Count(review => review.IsActive && review.IsVisible),
UserName = u.UserName,
Locations = (from ul in _dbContext.UserLocationRelationships
join l in _dbContext.Locations on ul.LocationId equals l.Id
where ul.IsActive && ul.UserId == u.Id
select new PartsPullerLocation
{
LocationId = ul.LocationId,
Name = ul.Location.Name
}),
Rating = u.GetPullerRating()
});
Now Here is my Extension.
public static int GetPullerRating(this User source)
{
var reviewCount = source.ReviewsReceived.Count(r => r.IsActive && r.IsVisible);
if (reviewCount == 0)
return 0;
var totalSum = source.ReviewsReceived.Where(r => r.IsActive && r.IsVisible).Sum(r => r.Rating);
var averageRating = totalSum / reviewCount;
return averageRating;
}
I have check this Post LINQ to Entities does not recognize the method
And I come to know I need to use
public System.Linq.Expressions.Expression<Func<Row52.Data.Entities.User, int>> GetPullerRatingtest
But how ?
Thanks
You can use conditionals inside LINQ to Entity queries:
AverageRating = u.ReviewsReceived.Count(r => r.IsActive && r.IsVisible) > 0 ?
u.ReviewsReceived.Where(r => r.IsActive && r.IsVisible).Sum(r => r.Rating) /
u.ReviewsReceived.Count(r => r.IsActive && r.IsVisible)
: 0
This will be calculated by the server, and returned as part of your list. Although with 10 million rows like you said, I would do some serious filtering before executing this.
Code within LINQ (to Entities) query is executed within database, so you can't put random C# code there. So you should either use user.GetPullerRating() after it is retrieved or create a property if you don't want to do the calculation every time.
You can also do:
foreach (var u in list)
u.Rating = u.GetPullerRating()
By the way, why is it extension method.

How to write Linq expression using external objects

I am trying to convert a loop in to a linq expression. But it seams not to work the way i am doing it:
var customer = GetCustomerFromDatabase(id);
ICollection<Order> customerOrders = null;
if (customer == null)
{
LogAndThrowCustomerNotFound(id);
}
else
{
customerOrders = customer.Orders;
}
customer.YearToDateSales = 0.0;
customer.CurrentSales = 0.0;
DateTime today = DateTime.Now;
if (customerOrders != null)
foreach (var order in customerOrders)
{
if (order.SubmittedDate != null
&& order.SubmittedDate.Value.Year.CompareTo(today.Year) == 0)
{
customer.YearToDateSales += (double)order.OrderTotal;
}
if (order.SubmittedDate != null
&& (order.SubmittedDate.Value.Month.CompareTo(today.Month) == 0
&& order.SubmittedDate.Value.Year.CompareTo(today.Year) == 0))
{
customer.CurrentSales += (double)order.OrderTotal;
}
}
So I came up with that expression to get the customer orders that match the current year... bot it does not work. in he expression order is empty and today is conflicting. I i create
DateTime today = DateTime.Now; in the parm of the expression i get different errors...
IEnumerable<Order> cOrders = customerOrders
.Where((ICollection<Order> order , today) =>
order.SubmittedDate.Value.Month == today.Month);
It's simpler if you just don't attempt pass today into the lambda, it'll be closed into the expression anyway;
customer.YearToDateSales = customerOrders
.Where(x => x.SubmittedDate != null &&
x.SubmittedDate.Value.Year == today.Year)
.Sum(x => x.OrderTotal);
customer.CurrentSales = customerOrders
.Where(x => x.SubmittedDate != null &&
x.SubmittedDate.Value.Month == today.Month &&
x.SubmittedDate.Value.Year == today.Year)
.Sum(x => x.OrderTotal);
Hard to tell exactly what's wrong without the error, but you probably need to check for null on the SubmittedDate like in the original version:
IEnumerable<Order> cOrders = customerOrders
.Where((ICollection<Order> order , today) =>
order.SubmittedDate.HasValue &&
order.SubmittedDate.Value.Month == today.Month);

Categories

Resources