LINQ to a model including List - c#

I would like to get your advice on Linq.
I have 3 tables users ( listing all the users), another one userEtablishments (one user can have many places), and the table Establishment (to list the place)
i have a models which is:
public class UserVM {
public Int32 id { get; set; }
public string name { get; set; }
public List<Etablishment> Etablishments { get; set; }
}
and the Etablishment:
public class EtablishmentVM {
public Int32 id { get; set; }
public string name { get; set; }
}
I query first the users, then establishments of the user, but its very slow:
UserVM obj = new UserVM();
using (context db = new context(ConnectionString))
{
userlist = (from u in db.users
join p in db.establishments on u.id equals p.id
join pe in db.userEtablishments on p.id equals pe.id
select new
{
u,
}).FirstOrDefault();
if (entity != null)
{
obj.id = entity.u.id);
obj.name = entity.u.name);
// Then get the establishment list then update the establishmentVM
List<EstablishmentVM> userplaces = new List<EstablishmentVM>();
var userplacesList = (from u in db.users join p in db.establishments on
u.id equals p.id join pe in db.userEtablishments on p.id equals pe.id
select new { u, pe }).ToList();
if (userplacesList != null && userplacesList.Count > 0)
{
foreach (var item in userplacesList)
{ }.....
is there a better way to do to get it execute faster ?
Any advices would helps, the purpose is to get betterperformances.
Thanks for your helps

Related

how to write an EF query to join three tables and order by a field?

I have the following 3 tables structured in the way as shown below. I am trying to write an entity framework join query among the 3 tables
to
Select joblink, usersubmitted, runstatus, submitted_time, changelist
orderby submitted time
I was able to join and retrieve data from 2 tables but cant figure out
on how to join 3 tables, can anyone provide guidance on how to do this?
lookahead_run (Table#1)
+-------------------+--------+----------------+-------------------+----------+
lookahead_run_id(PK)|joblink | usersubmitted |submitted_time |runstatus
+-------------------+--------+----------------+-------------------+----------+
15963---------------+link1---+---username1----+2017-03-17 22:28:53--Fail-----
lookahead_run_change_list (Table#2)
+---------------+----------------+-----------------+
changelistid(PK)|lookahead_run_id|change_list_id
+---------------+----------------+-----------------+
38591-----------+15963-----------+34022
38590-----------+15963-----------+34021
38589-----------+15963-----------+34020
change_lists (Table#3)
+-------------+-----------+
change_list_id|changelist
+-------------+-----------+
34022-------- 1823900
34021-------- 1819483
34020-------- 1818572
UPDATED CODE;-
namespace Dashboard.Model.ApiModels
{
public class LookaheadRunInfo
{
public string ECJobLink { get; set; }
public List<String> gerrits { get; set; }
public string UserSubmitted { get; set; }
public string SubmittedTime { get; set; }
public string RunStatus { get; set; }
}
}
public IEnumerable<LookaheadRunInfo> GetLookaheadRunInfoSearch(LookaheadRunsFilterCriteria filterCriteria)
{
List<LookaheadRunInfo> lookaheadRunsInfo = new List<LookaheadRunInfo>();
var lookaheadRunData = bitDB.lookahead_run.OrderBy(x => x.lookahead_run_id).Skip(filterCriteria.PageNumber * filterCriteria.PageSize).Take(filterCriteria.PageSize).ToList();
foreach (var lookaheadRunRow in lookaheadRunData)
{
var lookaheadRunId = lookaheadRunRow.lookahead_run_id;
lookaheadRunsInfo = (from lrcl in bitDB.lookahead_run_change_list
join cl in bitDB.change_lists on lrcl.change_list_id equals cl.change_list_id
join lr in bitDB.lookahead_run on lrcl.lookahead_run_id equals lr.lookahead_run_id
where lrcl.lookahead_run_id == lookaheadRunId
orderby lr.submission_time
select new LookaheadRunInfo
{
lr.ec_job_link,
cl.change_requests,
lr.submitted_by,
lr.submission_time,
lr.lookahead_run_status,
}).ToList();
}
return lookaheadRunsInfo;
}
Error:-
Error 1 Cannot initialize type 'Dashboard.Model.ApiModels.LookaheadRunInfo' with a collection initializer because it does not implement 'System.Collections.IEnumerable'
You can put as many joins as you like in a query. if you want to select fields from multiple entities, you need to select a new object. I would suggest you to create a holder class to contain the joined contents, but i'm gonna show you how to do it with an anonymous type:
var lookaheadRunChangeListIds = (from lrcl in bitDB.lookahead_run_change_list
join cl in bitDB.change_lists on lrcl.change_list_id equals cl.change_list_id
join lr in bitDB.lookahead_run on lrcl.lookahead_run_id equals lr.lookahead_run_id
where lrcl.lookahead_run_id == lookaheadRunId
orderby lr.submitted_time
select new LookaheadRunInfo {
ECJobLink = lr.joblink,
UserSubmitted = lr.usersubmitted,
RunStatus = lr.runstatus,
SubmittedTime = lr.submitted_time,
gerrits = cl.changelist
}).ToList();
Note that the new { ... } can be replaced by a new NewClass { ... } where the NewClass contains all the selected fields.
Edit above: name your properties as you instanciate your LookAheadRun since the names are different, you should map them.

one-to-many with Default

I have News. One news can have many Tags, Categories and Images. Special for it i thing about extended model.
public class NewsExt
{
public News News { get; set; }
public List<Categories> Categories { get; set; }
public List<Images> Images { get; set; }
public List<Tags> Tags { get; set; }
}
or
public class NewsExt
{
public Base.News News { get; set; }
public Categories Categories { get; set; }
public Images Images { get; set; }
public Tags Tags { get; set; }
}
I work with second variant and want something like this:
return
((from n in db.News
from i in db.Images.DefaultIfEmpty()
from t in db.Tags.DefaultIfEmpty()
from c in db.Categories.DefaultIfEmpty()
select new NewsExt()
{
News = n,
Images = i,
Tags = t,
Categories = c
}).GroupBy(news => news.News))
I want *Array of NewsExt** with one News and all other entities without repeating in each element of this array.
For the first viewmodel I try:
(from n in db.News
select new NewsExt()
{
News = n,
Images = (from i in db.Images.DefaultIfEmpty()
from n_i in db.News_Image
where n_i.news_id == n.id
select i).ToList(),
Tags = (from t in db.Tags.DefaultIfEmpty()
from n_t in db.News_Tag
where n_t.news_id == n.id
select t).ToList(),
Categories = (from c in db.Categories.DefaultIfEmpty()
from n_c in db.News_Category
where n_c.news_id == n.id
select c).ToList()
}).ToList();
But have excess records.
I decide to use first viewmodel.
(from n in db.News
select new NewsExt()
{
News = n,
Images = (from i in db.Images.DefaultIfEmpty()
join n_i in db.News_Image on i.id equals n_i.image_id
where n_i.news_id == n.id
select i).ToList(),
Tags = (from t in db.Tags.DefaultIfEmpty()
join n_t in db.News_Tag on t.id equals n_t.tag_id
where n_t.news_id == n.id
select t).ToList(),
Categories = (from c in db.Categories.DefaultIfEmpty()
join n_c in db.News_Category on c.id equals n_c.category_id
where n_c.news_id == n.id
select c).ToList()
}).ToList();

Store Linq Query in a list c#

I have this class from my entity Framework, i want to store this result of my linq query in list to display it in my web form, i get this error message:
Error 4 Cannot implicitly convert type
'System.Collections.Generic.List' to
'System.Collections.Generic.List' \App_Code\Models\PackageModel.cs
this is my code:
thanks for a helping.
public partial class Package
{
public int ID { get; set; }
public int SchoolID { get; set; }
public int SessionID { get; set; }
public int LessonsID { get; set; }
public virtual Lesson Lesson { get; set; }
public virtual School School { get; set; }
public virtual Session Session { get; set; }
}
public List<Package> GetAllItemPackage()
{
try
{
using (MusicSchoolEntities db = new MusicSchoolEntities())
{
List<Package> packages = (from x in db.Packages
join y in db.Schools on x.SchoolID equals y.ID
join z in db.Sessions on x.SessionID equals z.ID
join w in db.Lessons on x.LessonsID equals w.ID
join q in db.Courses on w.CourseID equals q.ID
select new { SchoolTitle = y.TitleEn ,
SessionName = z.NameEn,
CourseTitle = q.TitleEn,
LessonPeriod = w.PeriodEn,
LessonPrice = w.PriceEn,
LessonDesc = w.DescriptionEn,
LessonPaymtd = w.PayMtdEn}).ToList();
return packages;
}
}
catch (Exception)
{
return null;
}
}
You have 2 problems there.
First is that your code return an anonymous type but you are trying
to populate a List<Package> - That is why you get the exception.
Secondly, the data you are trying to populate isn't like the Package class that you have so if you want to return such a list from a function you should create a new type of class to have all those properties.
So:
List<YourClass> packages = (from x in db.Packages
join y in db.Schools on x.SchoolID equals y.ID
join z in db.Sessions on x.SessionID equals z.ID
join w in db.Lessons on x.LessonsID equals w.ID
join q in db.Courses on w.CourseID equals q.ID
select new YourClass
{
SchoolTitle = y.TitleEn ,
SessionName = z.NameEn,
CourseTitle = q.TitleEn,
LessonPeriod = w.PeriodEn,
LessonPrice = w.PriceEn,
LessonDesc = w.DescriptionEn,
LessonPaymtd = w.PayMtdEn
}).ToList();
return packages;
And of course GetAllItemPackage should return: List<YourClass> and not List<Package>

Linq - Join where ID's !=, select new + distinct?

I have the following classes.
Course;
public class Course
{
//pk
public int Id{ get; set; }
public int SourceCourseId { get; set; }
public string Name { get; set; }
}
Registration
public class Registration
{
//primary key
public int Id { get; set; }
//...more fields
public int CourseId { get; set; }
}
I want to obtain a collection of annonymous objects with the two fields below for all Courses that are Distinct in the registrations table that are not in the Courses table.
var distinctCourses = (from registration in db.Registrations
join courses in db.Courses on registration.CourseId equals courses.SourceCourseId
where registration.CourseId != courses.SourceCourseId
select new
{
SourceCourseId = registration.CourseId,
Name = registration.CourseName,
}).Distinct().ToList();
For some reason the above is returning 0... Any suggestions?
try a left join:
var query = from r in registrations
join c in courses on r.CourseId equals c.id into newCourses
from nullCourse in newCourses.DefaultIfEmpty()
where nullCourse == null
select new { }
Edit - per comment from Alex :
Also, your where clause needs to change to
where nullCourse == null
Edit - changed join columns and added correct where clause.
Edit - group registrations on CourseID so they will be distinct
var distinctCourses =
(from registration in db.Registrations
group registration by registration.CourseId into grp
from reg in grp
join courses in db.Courses on reg.CourseId equals courses.SourceCourseId into newCourses
from nullCourse in newCourses.DefaultIfEmpty()
where nullCourse == null
select new
{
SourceCourseId = reg.CourseId,
Name = reg.CourseName,
}).ToList();
Try this
var result = Registrations.GroupJoin(Courses,r=>r.CourseId,c=>c.SourceCourseId,
(k,g) => new {k,g})
.Where(x=>x.g.Count()==0)
.Select(s=> new {id=s.k.CourseId,name=s.k.CourseName});

Need help creating complex ef linq select

Hello i am having some problems creating an complex Linq with multible joins and left joins.
I have 4 tables as listed in the end, what this is used for is to see how i need to send an email about a new reply to a topic. So i fetch all Posts from the topic joined by the user. The same user can ofcause have more then 1 post in each topic.
After that i join with UserEmailSetting, this is to see if the user have oped out reciving email notifications. Lastly i need to know if an email have been send to the user notifying about the new reply (I don't want to spam my users if there are made a lot of replys), so if an reply notification have been sendt since the last visit to the site I don't want to send another mail. Here is my try that works, but i would like to optimate it!
The problem is that there can be many results on the UserEmailSetting, so i get alot os results back when i infact only get 1 or 2 back.
here is my attept
var select = (from p in ForumPostRepository.Get()
join u in UserRepository.Get() on p.UserId equals u.Id
join ues in UsersEmailSettingRepository.Get() on u.Id equals ues.UserId
join els in
(from _el in EmailLogRepository.Get()
where _el.Type == "ReplyToTopic" &&
_el.Values == topicId
orderby _el.Id descending
select _el) on u.Id equals els.UserId
into emailLogs
from el in emailLogs.DefaultIfEmpty()
where p.TopicId == forumTopic.Id &&
ues.ReplyToTopic //&& // We only want people who need notifications
//!u.Online // We only want people who are not online
orderby p.Id descending, el.Id descending
select new
{
User = u,
EmailLog = el
});
var result = select.DistinctBy(x => x.User.Id).ToList();
Here are the database classes
public class ForumPost
{
public int? TopicId { get; set; }
public int UserId { get; set; }
...
}
public class User
{
public int Id { get; set; }
public bool Online { get; set; }
public DateTime LastLogin { get; set; }
...
}
public class UsersEmailSetting
{
public int UserId { get; set; }
public bool ReplyToTopic { get; set; }
}
public class EmailLog
{
public int Id { get; set; }
public int UserId { get; set; }
public string Type { get; set; }
public string Values { get; set; }
public DateTime Created { get; set; }
}
Updata: a bit more structured layout of what i want the linq to do, I hope It helps
Get all posts from ForumPostRepository where topicId is 13
Join with UserRepository on ForumPostRepository.UserId = UserRepository.Id
Now I only want unike users
Join with UsersEmailSettingRepository on UserRepository.Id =
UsersEmailSettingRepository.UserId
Left join with EmailLogRepository on UserRepository.Id =
EmailLogRepository.UserId AND EmailLogRepository.Type =
“ReplyToTopic” AND EmailLogRepository.Values = “topicId”
-> Now there can be anywhere from 0 to * results on this request, I only want the latest!
No guarantees that this will be performant.
var users = UserRepository.Get();
var userEmailSettings = UsersEmailSettingRepository.Get();
var emailLogs = EmailLogRepository.Get();
var posts = ForumPostRepository.Get();
var foo =
from user in users
where posts
.Any(post => post.UserId == u.Id && post.TopicId == topicId)
where userEmailSettings
.Any(ues => u.Id equals ues.UserId && ues.ReplyToTopic == true)
where false ==
(
from el in emailLogs
where el.Type == "ReplyToTopic"
&& el.Values == topicId
&& el.UserId == user.Id
&& el.Created > user.LastLogin
select el
).Any()
select user;
Signed
A Linq Ninja
edit: just saw that you don't have navigation properties.

Categories