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
Related
Good Day To you all
I have issue with using 'predicate'
I'm trying to make function to return the results of some search text
here is the body of the function
public List<SaddadVM> GetAllBills(int Page = 1, int Take = 10, int? SearchField = null, string SearchItem = null)
{
var predicate = PredicateBuilder.New<SaddadVM>();
if (!string.IsNullOrWhiteSpace(SearchItem))
{
predicate = predicate.And(x => x.BillAcct == SearchItem);
}
predicate = predicate.And(x => x.Id != 0);
var bill = (from d in _context.Saddad
join R in _context.Requests on d.ReqId equals R.Id
join l in _context.Documenter on R.DocumenterId equals l.Id
where d.RecordStatus != GeneralEnums.RecordStatus.Deleted
select new SaddadVM
{
BillAcct = d.BillAcct,
ReqID = d.ReqId,
DocName = l.FullName,
DueDt = d.DueDt,
BillAmount = d.BillAmount
}).Where(predicate).Skip((Page - 1) * Take).Take(Take).ToList();
return bill;
}
Knowing that the the Bill object should return at least 2 depending on running the same query on DB as follows :
enter image description here
I want to assign GetMajorMileStone(projecttask.ProjectTaskId) result to MajorMilestone.
I tried but getting following error:
LINQ to Entities does not recognize the method
'System.Data.Objects.ObjectResult1[.Poco.GetMajorMileStone_Result]
GetMajorMileStone(System.Nullable1[System.Guid])' method, and this
method cannot be translated into a store expression.'
Here is my code:
public ProjectsPayload GetProjectSchedule(int projectid, bool includeArchived, DateTime startDate, DateTime endDate, int userId)
{
using (var db = new Entities())
{
try
{
db.CommandTimeout = 1200;
var query = from project in db.Project.Where(t => (t.Active || t.TempActive) && t.ProjectId == projectid)
join UP in db.User_X_Project on project.ProjectId equals UP.ProjectId
where (UP.UserId == userId && UP.Active)
orderby (project.Priority ?? int.MaxValue)
orderby (project.ProjectTitle)
select new
{
Project = project,
ProjectTask = from projecttask in project.ProjectTask.Where(t => t.Active && (
(includeArchived == true && t.TaskStatusId == (int?)TaskStatus.Archived) ||
(includeArchived == false && t.TaskStatusId != (int?)TaskStatus.Archived))
|| t.TaskStatusId != (int?)TaskStatus.Planned)
join schedule in project.ProjectTask.SelectMany(p => p.ProjectTaskSchedule) on projecttask.ProjectTaskId equals schedule.ProjectTaskId
join daily in db.ProjectTaskSchedule.SelectMany(p => p.DailyStatus) on schedule.ProjectTaskScheduleId equals daily.ProjectTaskScheduleId
where schedule.Active && daily.Active && projecttask.Active && schedule.ResourceId == userId && (
(EntityFunctions.TruncateTime(daily.Date) >= EntityFunctions.TruncateTime(startDate.Date) &&
EntityFunctions.TruncateTime(daily.Date) <= EntityFunctions.TruncateTime(endDate.Date))
)
orderby schedule.StartDate
select new
{
ProjectTask = projecttask,
ProjectTaskSchedule = from projecttaskschedule in projecttask.ProjectTaskSchedule.Where(t => t.Active && t.ResourceId == userId)
select new
{
ProjectTaskSchedule = projecttaskschedule,
DailyStatus = projecttaskschedule.DailyStatus.Where(t => t.Active),
},
CritiCality = from cr in db.CritiCality.Where(ts => ts.ProjectTaskId == projecttask.ProjectTaskId) select cr,
MMDetails = from mm in db.MMDetails.Where(ts => ts.ProjectTaskId == projecttask.ProjectTaskId) select mm,
MajorMilestone = db.GetMajorMileStone(projecttask.ProjectTaskId).FirstOrDefault(),
}
};
var materialized = query.AsEnumerable();
var result = materialized.Select(t => new ProjectsPayload
{
ProjectId = t.Project.ProjectId,
ProjectTitle = t.Project.ProjectTitle,
Priority = t.Project.Priority,
ProjectDescription = t.Project.ProjectDescription,
ProjectTask = t.Project.ProjectTask.Select(x => new ProjectTaskPayload
{
Duration = x.Duration,
Hours = x.Hours,
IsOngoing = x.IsOngoing,
IsSummaryTask = x.IsSummaryTask,
Priority = x.Priority,
ParentTaskId = x.ParentTaskId,
ProjectId = x.ProjectId,
ProjectTaskId = x.ProjectTaskId,
TaskAcceptanceId = x.TaskAcceptanceId,
TaskStatusId = x.TaskStatusId,
TaskTitle = x.TaskTitle,
TaskTypeId = x.TaskTypeId,
IsMileStone = x.IsMileStone,
IsTimeAwayTask = x.IsTimeAwayTask,
AutoSize = x.AutoSize,
IsArchivedTasksInSummary = x.IsArchivedTasksInSummary,
IsASAP = x.IsASAP,
IsAutoCompleteEnable = x.IsAutoCompleteEnable,
IsSharedDiffSchedules = x.IsSharedDiffSchedules,
LongDescription = x.LongDescription,
OwnerId = x.OwnerId,
ShowInSummaryTask = x.ShowInSummaryTask,
SubTypeID = x.SubTypeID,
MMDetails1 = x.MMDetails1.Select(MD => new MMDetailsPayload { MajorMilestoneId = MD.MajorMilestoneId, ProjectTaskId = MD.ProjectTaskId, MMDetailsId = MD.MMDetailsId, Slack = MD.Slack }),
ProjectTaskSchedule = x.ProjectTaskSchedule.Select(a => new ProjectsTaskSchedulePayload
{
ProjectTaskScheduleId = a.ProjectTaskScheduleId,
StartDate = a.StartDate,
EndDate = a.EndDate,
ProjectTaskId = a.ProjectTaskId,
ResourceId = a.ResourceId,
ArchiveEndDate = a.ArchiveEndDate,
ArchiveStartDate = a.ArchiveStartDate,
IsSharedTask = a.IsSharedTask,
TimeUnitId = a.TimeUnitId,
DailyStatus = a.DailyStatus.Select(Ds => new DailyStatusPayload
{
Active = Ds.Active,
ActualHours = Ds.ActualHours,
DailyStatusId = Ds.DailyStatusId,
Date = Ds.Date,
ProjectTaskScheduleId = Ds.ProjectTaskScheduleId,
IsCloseOutDay = Ds.IsCloseOutDay,
Priority = Ds.Priority
})
}).ToList(),
CritiCality = x.CritiCality.Select(c => new CriticalityPayload { CriticalityId = c.CriticalityId, CriticalityTypeId = c.CriticalityTypeId, ProjectTaskId = c.ProjectTaskId }).ToList(),
}).ToList()
}).FirstOrDefault();
return result;
}
catch (EntityException ex)
{
if (ex.Message == connectionException)
throw new FaultException(dbException);
else
throw new FaultException(ex.Message);
}
}
}
My result is like this, I want all entities(Criticality,MMDetails and MajorMileStone), Not only MajorMileStone
MajorMileStone Result
I separate multiple simple query for testing. Please try to execute below two query and check whether successful or not.
// First query to get project
var query1 = from project in db.Project.Where(t => (t.Active || t.TempActive) && t.ProjectId == projectid)
join UP in db.User_X_Project on project.ProjectId equals UP.ProjectId
where (UP.UserId == userId && UP.Active)
orderby (project.Priority ?? int.MaxValue)
orderby (project.ProjectTitle)
.Select new { project = project }.ToList();
// Second query to get projecttask from query1.project and execute store procedure
var query2 = from projecttask in query1.project.ProjectTask.Where(t => t.Active && (
(includeArchived == true && t.TaskStatusId == (int?)TaskStatus.Archived) ||
(includeArchived == false && t.TaskStatusId != (int?)TaskStatus.Archived)) ||
t.TaskStatusId != (int?)TaskStatus.Planned)
join schedule in query1.project.ProjectTask.SelectMany(p => p.ProjectTaskSchedule) on projecttask.ProjectTaskId equals schedule.ProjectTaskId
join daily in db.ProjectTaskSchedule.SelectMany(p => p.DailyStatus) on schedule.ProjectTaskScheduleId equals daily.ProjectTaskScheduleId
where schedule.Active && daily.Active && projecttask.Active && schedule.ResourceId == userId && (
(EntityFunctions.TruncateTime(daily.Date) >= EntityFunctions.TruncateTime(startDate.Date) &&
EntityFunctions.TruncateTime(daily.Date) <= EntityFunctions.TruncateTime(endDate.Date))
)
orderby schedule.StartDate
.Select new
{
MajorMilestone = db.GetMajorMileStone(projecttask.ProjectTaskId).FirstOrDefault(),
}.ToList();
Let me know it has result or not. In the meantime you can check this "Method cannot be translated into a store expression"
It has link to article about what not to do with linq. Nested Linq like this is best to avoid and better to split up the query. If it affects the execution time, it better to execute raw sql.
I have a query in Lambda expression. i want to encode a properties which in two step inner in query.
The sample code is
public List<StudentCreativeQuestionListViewModel> GetCreativeQuestionsByQuestionSetId(long studentId,
long questionSetId)
{
var questionList =
UnitOfWork.StudentExamRepository.GetCreativeQuestionsByQuestionSetId(studentId, questionSetId);
List<StudentCreativeQuestionListViewModel> encryptQuestionList = questionList.Select(q =>
{
q.Questions = q.Questions.Select(t =>
{
t.TutorialList.Select(x =>
{
x.FileName = x.FileName.ToEncode();
return x;
});
return t;
});
return q;
}).ToList();
return encryptQuestionList.ToList();
}
and GetCreativeQuestionsByQuestionSetId exist in another layer having code:
public IEnumerable<StudentCreativeQuestionListViewModel> GetCreativeQuestionsByQuestionSetId(long studentId, long questionSetId)
{
bool isPurchased = this.IsPurchased(studentId);
var data = (from question in Context.Question
join questionSetQuestion in Context.QuestionSetQuestion on question.Id equals questionSetQuestion
.QuestionId
where questionSetQuestion.QuestionSetId == questionSetId && question.IsArchived == false
select new StudentCreativeQuestionListViewModel
{
Id = question.Id,
Name = question.Name,
Mark = questionSetQuestion.Mark,
LastUpdateDate = question.LastUpdateDate,
ImageUrl = question.ImageUrl,
Questions = Context.CreativeQuestion.Where(qa => qa.QuestionId == question.Id).AsEnumerable()
.Select(cq => new CreativeQuestionViewModel
{
Id = cq.Id,
Name = cq.Name,
TutorialList = (from aSuggestion in Context.AnswerSuggestion
join t in Context.Tutorial on aSuggestion.TutorialId equals t.Id
where aSuggestion.CreativeQuestionId == cq.Id &&
t.TutorialType >= TutorialType.Video &&
t.TutorialType <= TutorialType.Link
group t by t.TutorialType into grp
select grp.OrderBy(g => g.TutorialType).FirstOrDefault() into tutorial
join st in Context.StudentTutorial.Where(s => s.StudentId == studentId) on tutorial.Id equals st.TutorialId into sTutorialTemp
from sTutorial in sTutorialTemp.DefaultIfEmpty()
join topic in Context.Topic on tutorial.TopicId equals topic.Id into topicGroup
from tp in topicGroup.DefaultIfEmpty()
join chapter in Context.Chapter on tutorial.ChapterId equals chapter.Id into chapterGrp
from c in chapterGrp.DefaultIfEmpty()
join bk in Context.Bookmark on tutorial.Id equals bk.TutorialId into tempBk
from bookmark in tempBk.Where(t => t.StudentId == studentId).DefaultIfEmpty()
select new TutorialListViewModel
{
Id = tutorial.Id,
Body = tutorial.Body,
Heading = tutorial.Heading,
FileName = tutorial.FileName,
ThumbUrl = tutorial.ThumbUrl,
ChapterName = c.Name,
TutorialType = tutorial.TutorialType,
DurationInSecond = tutorial.DurationInSecond,
TopicId = tutorial.TopicId,
Sequence = tp != null ? tp.SequenceNumber:0,
IsLocked = tutorial.IsLocked && !isPurchased,
IsCompleted = sTutorial != null && sTutorial.IsCompleted,
IsBookmark = bookmark != null
}).ToList()
}).ToList()
}).AsEnumerable();
return data;
}
Here show the error to cast this query. the message shown:
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)
I think what you are doing with q.Questions = q.Questions.Select(t =>... while creating the encryptedQuestionList is causing the cast exception as the 'q.Questions' is of type 'List' and you are trying to assign an 'IEnumerable' to it within that query.
The encryptedQuestionList query can be written like this:
List<StudentCreativeQuestionListViewModel> encryptQuestionList = questionList.Select(q =>
{
q.Questions.Select(t =>
{
t.TutorialList.Select(x =>
{
x.FileName = x.FileName.ToEncode();
return x;
});
return t;
});
return q;
}).ToList();
List<StudentCreativeQuestionListViewModel> encryptQuestionList = questionList.Select(q =>
{
q.Questions = q.Questions.Select(t =>
{
t.TutorialList = t.TutorialList.Select(x =>
{
x.FileName = x.FileName.ToEncode();
return x;
}).ToList();
return t;
}).ToList();
return q;
}).ToList();
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.
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
}