LINQ to Entities does not recognize the method - c#

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.

Related

Adding Summed columns together using Linq

I am wondering if there is an easier way of adding together summed columns inside a group by query using Linq. I am wanting to check wether column1 + column2 is greater than 2250, and if so do something...
Below is a snippet of code im using, a much slimmed down version for use here
from contact in _db.Worksheets
join person in _db.MyTable on contact.Email equals
person.EmailAddress
orderby contact.ShiftDate ascending
select new
{
EmployeeNumber = person.EmployeeNumber,
Overtime1= contact.Overtime1,
Overtime2= contact.Overtime2,
ShiftDate = contact.ShiftDate,
} into t1
group t1 by t1.EmployeeNumber into pg
select (new
{
OvertimeTotal = pg.Sum(x => x.ShiftDate >= vStart1 && x.ShiftDate <= vEnd1 ? x.Overtime1 : 0)
+ pg.Sum(x => x.ShiftDate >= vStart1 && x.ShiftDate <= vEnd1 ? x.Overtime2 : 0) > 2250 (....then do something)
I was wondering if you could do something like the below. (Which I have tried and it doesnt work)
I am using entity framework too, so realise there may be complications converting this type of query
OvertimeTotal = pg.Sum(x => x.ShiftDate >= vStart1 && x.ShiftDate <= vEnd1 ? x.Overtime1 + x.Overtime2 : 0)
It would help if you specify what you want when there is overtime. The following will return the employee numbers with overtime.
The approach is a little different from yours, as it filters the worksheet records before joining with the person records for optimization reasons. It then filters to just the employees that have overtime.
I'm assuming an employee has overtime if overtime1 + overtime2 of all their shifts in the specified date range adds up to more than 2250.
var employeesWithOvertime = _db.Worksheets
.Where(w => w.ShiftDate >= vStart1 && w.ShiftDate <= vEnd1)
.Join(_db.MyTable, w => w.Email, p => p.EmailAddress, (w, p) => new
{
EmployeeNumber = p.EmployeeNumber,
Overtime1 = w.Overtime1,
Overtime2 = w.Overtime2
})
.GroupBy(x => x.EmployeeNumber)
.Select(g => new
{
EmployeeNumber = g.Key,
OvertimeTotal = g.Sum(x => x.Overtime1 + x.Overtime2)
})
.Where(x => x.OvertimeTotal > 2250);

How to call a local method from the linq query

In my web api i need to execute a method from linq query itself. My linq query code snippet belongs to method is shown below which calls local method to get required data.
var onlineData = (from od in db.RTLS_ONLINEPERSONSTATUS
let zoneIds = db.RTLS_PERSONSTATUS_HISTORY.Where(p => p.person_id == od.PERSONID).OrderByDescending(z => z.stime > startOfThisDay && z.stime < DateTime.Now).Select(z => z.zone_id).ToList()
let zoneIdsArray = this.getZoneList((zoneIds.ToArray()))
let fzones = zoneIdsArray.Select(z => z).Take(5)
select new OnlineDataInfoDTO
{
P_ID = od.PERSONID,
T_ID = (int)od.TAGID,
LOCS = fzones.ToList()
}
public int[] getZoneList(decimal[] zoneIdsArray)
{
int[] zoneIds = Array.ConvertAll(zoneIdsArray, x => (int)x);
List<int> list = zoneIds.ToList();
for (int c = 1; c < zoneIdsArray.Count(); c++)
{
if (zoneIdsArray[c] == zoneIdsArray[c - 1])
{
list.Remove((int)zoneIdsArray[c]);
}
}
return list.ToArray();
}
I am getting exception at let zoneIdsArray = this.getZoneList((zoneIds.ToArray())), is there any way to solve this problem. I got logic to solve my problem from this link(Linq query to get person visited zones of current day ), the given logic is absolutely fine for my requirement but i am facing problem while executing it.
One way to achieve that would be to perform the projection on the client instead of the underlying LINQ provider. This can be done by separating your query into 2 steps:
var peopleStatus =
from od in db.RTLS_ONLINEPERSONSTATUS
let zoneIds = db.RTLS_PERSONSTATUS_HISTORY
.Where(p => p.person_id == od.PERSONID)
.OrderByDescending(z => z.stime > startOfThisDay && z.stime < DateTime.Now)
.Select(z => z.zone_id)
.ToList()
select new
{
Person = od,
ZoneIds = zoneIds,
};
var onlineData =
from od in peopleStatus.ToList()
let zoneIdsArray = this.getZoneList((od.ZoneIds.ToArray()))
let fzones = zoneIdsArray.Select(z => z).Take(5)
select new OnlineDataInfoDTO
{
P_ID = od.Person.PERSONID,
T_ID = (int)od.Person.TAGID,
LOCS = fzones.ToList()
};

Linq Subquery in IQueryable Select

I am having problems with subqueries in a linq-to-entities IQueryable query.
Can anybody tell me what is the correct way to do a sub query when building up an IQueryable query? Based on my full example below.
I get the following error when ToArray() is called on the query:
An exception of type 'System.NotSupportedException' occurred in System.Data.Entity.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method 'System.Data.Entity.IDbSet`1[MyDomain.NewsWorthyPressReleases.NewsWorthyWire] Set[NewsWorthyWire]()' method,
and this method cannot be translated into a store expression.
So for example you can see one of my subqueries here:
BwIncluded = (from abw in Context.Set<NewsWorthyWire>()
where abw.WireId == PressWireIds.BUID
where abw.NewsWorthyCampaignId == nc.Id
select abw).Any(),
I am trying to populate BwIncluded with true or false if any() exists.
And the entire build up of the query is as follows, it is IMPORTANT to understand where the sub-queries are used:
private Func<EntityFramework.IDbContext, IQueryable<NewsWorthyPressRelease>> GetSearchNewsWorthyQuery(NewsWorthySearchFields searchFields)
{
return context =>
{
//domain models
var newsWorthyCampaigns = context.Set<NewsWorthyCampaign>();
var wires = context.Set<NewsWorthyWire>();
var campaigns = context.Set<Campaign>();
//predicates
var newsWorthyCampaignPredicate = PredicateBuilder.True<NewsWorthyCampaign>();
var wirePredicate = PredicateBuilder.True<NewsWorthyWire>();
var campaignPredicate = PredicateBuilder.True<Campaign>();
// build up the predicate queries
//Status was input
if (searchFields.StatusId.HasValue && searchFields.StatusId.Value > 0)
{
newsWorthyCampaignPredicate = newsWorthyCampaignPredicate.And(x => x.Id == searchFields.StatusId);
}
//Id was input
if (searchFields.Id.HasValue && searchFields.Id.Value > 0)
{
wirePredicate = wirePredicate.And(x => x.Id == searchFields.Id);
}
//Title was input
if (!string.IsNullOrEmpty(searchFields.Title))
{
wirePredicate = wirePredicate.And(x => x.Title.Contains(searchFields.Title));
}
//Wire was input
if (searchFields.PressWireId.HasValue && searchFields.PressWireId.Value > 0)
{
wirePredicate = wirePredicate.And(x => x.Id == searchFields.PressWireId);
}
//Created By was chosen
if (searchFields.CreatedById.HasValue && searchFields.CreatedById.Value > 0)
{
campaignPredicate = campaignPredicate.And(x => x.IdentityId == searchFields.CreatedById);
}
//Create Date From was chosen
if (searchFields.DateCreatedFrom.HasValue)
{
campaignPredicate = campaignPredicate.And(y => y.CreationDate >= searchFields.DateCreatedFrom);
}
//Create Date To was chosen
if (searchFields.DateCreatedTo.HasValue)
{
campaignPredicate = campaignPredicate.And(y => y.CreationDate <= searchFields.DateCreatedTo);
}
//the query
var nwprQuery = (from nc in newsWorthyCampaigns.Where(newsWorthyCampaignPredicate)
join w in wires.Where(wirePredicate)
on nc.Id equals w.NewsWorthyCampaignId
join c in campaigns.Where(campaignPredicate)
on nc.CampaignId equals c.Id
select new NewsWorthyPressRelease
{
Id = nc.Id,
Title = w.Title,
//BwIncluded = false,
//GnIncluded = false,
//PrIncluded = false,
BwIncluded = (from abw in Context.Set<NewsWorthyWire>()
where abw.WireId == PressWireIds.BUID
where abw.NewsWorthyCampaignId == nc.Id
select abw).Any(),
GnIncluded = (from agw in Context.Set<NewsWorthyWire>()
where agw.WireId == PressWireIds.GLID
where agw.NewsWorthyCampaignId == nc.Id
select agw).Any(),
PrIncluded = (from anw in Context.Set<NewsWorthyWire>()
where anw.WireId == PressWireIds.PRID
where anw.NewsWorthyCampaignId == nc.Id
select anw).Any(),
CreatedBy = c.CreatedBy.FirstName + " " + c.CreatedBy.Surname,
CreateDate = c.CreationDate,
Status = nc.NewsWorthyStatus.Name,
}).AsNoTracking();
return nwprQuery;
};
}
Can anyone help with this?
Thanks

Comma separated List in linq select

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.

Using .include(),.where(),.select() for LINQ query

I have a query like this:
var rrx = (from camp in db.Campus
join camproom in db.CampusRooms
on camp.Id equals camproom.CampusId
where (camproom.CampusId == 1) && (camp.BranchId == 10) && (camproom.Status == 0)
select new CampusCampusRoom { CampName = camp.Name, CampusRoomNo = camproom.RoomNo, CampusClassCapacity = camproom.ClassCapacity, CampusExamCapacity = camproom.ExamCapacity }).ToList();
How can I perform this query using .include(), .where(), .select() clauses?
Here is an easy to use filtered projection example. This should provide you with a good example of what you want to do with your query.:
var customersWithRecentReservations =
from c in context.Contacts.OfType<Customer>()
where c.FirstName == p_firstName && c.LastName == p_lastName
select new {Customer = c, Reservations = c.Reservations.Where(r => r.ReservationDate >= p_reservationDate)};
var customers = customersWithRecentReservations.AsEnumerable().Select(p => p.Customer);
Try and adapt this code to your situation or let me know if you need further assistance with it ;)

Categories

Resources