How to call a local method from the linq query - c#

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

Related

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

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.

convert sql to linq with two tables

select ind.desc,ind.number
from int_goals_df idd, goals_df ind
where idd.dld_number = 123456
and ind.number = idd.ind_number
and ind.categorie = 2
order by follownumber
I'm having a hard time translating this to linq since it is using two tables.
I've currently solved this now imperatively with a foreach loop but not happy with it..
I'm trying to get a list of goals_df that matches with a list of int_goals_df.
Any tips would be greatly appreciated ! Thank you !
EDIT - here is the code I'm using:
//get current GoalDefinitions by selected Goal
var currentGoalDefinition = MyAppAppContext.MyAppAppContextInstance.MyAppContext.GoalDefinitions.FirstOrDefault(
d => d.DLD_GoalDFID == interv.Goal.DLD_GoalenDFID);
// get current intervGoalDefinitions by GoalDefinition
var currentintervGoalDefinitions = MyAppAppContext.MyAppAppContextInstance.MyAppContext.intervGoalDefinitions.Where(
idd => idd.DLD_GoalDFID == currentGoalDefinition.DLD_GoalDFID).OrderBy(idd => idd.IDD_VolgNummer);
intervDefinitionCollection = new ObservableCollection<intervDefinition>(MyAppAppContext.MyAppAppContextInstance.MyAppContext.intervDefinitions.Where(i => i.IND_Categorie == intCategorie));
// filter intervGoalDefinitions by intervDefinitions
var intervDefinitionCollectionTemp = new ObservableCollection<intervDefinition>();
foreach (var currentintervGoalDefinity in currentintervGoalDefinitions)
{
var foundintervGoalDefinitySorted = intervDefinitionCollection.FirstOrDefault(
i => i.IND_intervDFID == currentintervGoalDefinity.IND_intervDFID);
if (foundintervGoalDefinitySorted != null)
intervDefinitionCollectionTemp.Add(foundintervGoalDefinitySorted);
}
intervDefinitionCollection = intervDefinitionCollectionTemp;
assuming NHibernate as ORM and int_goal is a subclass of goal
var results = from idd in session.Query<IntGoals>()
where idd.DlDNumber = 123456 && idd.Category.Id == 2
orderby idd.FollowNumber
select new { idd.Description, idd.Number };
context.int_goals_df.Join(context.goals_df, x => x.ind_number, x => x.number,
(x, y) => new
{
idd = x,
ind = y
})
.Where(x => x.idd.dld_number = 123456 && x.ind.categorie = 2)
.OrderBy(x => x.idd.follownumber)
.Select(x => new
{
x.ind.desc,
x.ind.number
});
quick go - think you need the join
var results = from idd in session.Query<int_goals_df>()
join ind in session.Query<goals_df>()
on idd.ind_number equals ind.ind_number
where idd.DlDNumber = 123456 && idd.Category.Id == 2
orderby idd.FollowNumber
select new { idd.Description, idd.Number };
I tend to use the sql syntax without implicit joins
/*Fields*/
SELECT ind.desc, ind.number
/*Tables*/
FROM int_goals_df idd
INNER JOIN goals_df ind
ON ind.number = idd.ind_number
/*Conditions*/
WHERE idd.dld_number = 123456
AND ind.categorie = 2
/*Order/Grouping*/
ORDER BY follownumber
You can see from Chris's answer this translates more easily to linq.

Select top n rows in each group in EntityFramework

I'm trying to fetch recent contents of each type, currently I'm using something similar to the following code to fetch n records for each type
int n = 10;
var contents = Entities.OrderByDescending(i => i.Date);
IQueryable<Content> query = null;
for (int i = 1; i<=5; i++)
{
if (query == null)
{
query = contents.Where(c => c.ContentTypeIndex == i).Take(n);
}
else
{
query = query.Concat(contents.Where(c => c.ContentTypeIndex == i).Take(n));
}
}
One other solution can be creating an SP, but is it possible to do it by grouping in EF? If not, any cleaner solution?
contents.Where(c => c.ContentTypeIndex >= 1 && c.ContentTypeIndex <= 5)
.GroupBy(c => c.ContentTypeIndex)
.SelectMany(g => g.Take(n));
Note: if you want to select all types of indexes, then you don't need where filter here.

linq if statement, or stored procedure if statements

I am looking to run a piece of code in the database. However there is no supported translation to sql (using linq to sql).
How to convert this code logic ro either inline in linq or in a stored procedure? I have no knowledge of db and stored procedures so preferably I would like to write it in linq.
public Post GetPageOwner(int pageid)
{
var posts = (from dp in db.Posts where dp.pageid == pageid select dp);
var returned = posts;
if (posts.Count() > 0)
{
var latest = posts.OrderByDescending(o => o.Date).FirstOrDefault();
var sharedsamedayaslatest = (from p in posts where p.Date.AddDays(1) >= latest.Date select p);
if (sharedsamedayaslatest.Count() > 1)
{
var followedpost = (from p in posts from s in db.Subscriptions where s.Subscriber == UID && s.Subscribedto == p.UserId select p);
var count = followedpost.Count();
if (count == 1)
{
returned = followedpost;
}
else if (count > 1)
{
returned = (from s in followedpost let reposts = GetPostReposts(s.id) let rating = GetPostRating(s.id) let score = reposts + rating orderby score descending select s);
}
else
{
//no follower shared this post so return the most liked
returned = (from s in sharedsamedayaslatest let reposts = GetPostReposts(s.id) let rating = GetPostRating(s.id) let score = reposts + rating orderby score descending select s);
}
}
else
{
//no shares on the day the latest share
returned = sharedsamedayaslatest;
}
}
else
{
//only one post
returned = posts;
}
return returned.FirstOrDefault(); //order by userid gets a random one
}
May be something like this would work:
public Post GetPageOwner(int pageid)
{
var posts = (from dp in db.Posts where dp.pageid == pageid select dp);
var returned = posts;
if (posts.Count() > 0)
{
var latest = posts.OrderByDescending(o => o.Date).FirstOrDefault();
var sharedsamedayaslatest = (posts.Where(p => p.Date.AddDays(1) >= latest.Date));
if (sharedsamedayaslatest.Count() > 1)
{
var followedpost = (posts.SelectMany(p => db.Subscriptions, (p, s) => new {p, s}).Where(
#t => s.Subscriber == UID && s.Subscribedto == p.UserId).Select(#t => p));
var count = followedpost.Count();
if (count == 1)
{
returned = followedpost;
}
else if (count > 1)
{
returned = (followedpost.Select(s => new {s, reposts = GetPostReposts(s.id)}).Select(
#t => new {#t, rating = GetPostRating(s.id)}).Select(
#t => new {#t, score = reposts + rating}).OrderByDescending(#t => score).Select(#t => s));
}
else
{
//no follower shared this post so return the most liked
(sharedsamedayaslatest.Select(s => new {s, reposts = GetPostReposts(s.id)}).Select(
#t => new {#t, rating = GetPostRating(s.id)}).Select(
#t => new {#t, score = reposts + rating}).OrderByDescending(#t => score).Select(#t => s)) = returned;
}
}
else
{
//no shares on the day the latest share
returned = sharedsamedayaslatest;
}
}
else
{
//only one post
returned = posts;
}
return returned.FirstOrDefault(); //order by userid gets a random one
}

Categories

Resources