LINQ: dot notation equivalent for JOIN - c#

Consider this LINQ expression written using query notation:
List<Person> pr = (from p in db.Persons
join e in db.PersonExceptions
on p.ID equals e.PersonID
where e.CreatedOn >= fromDate
orderby e.CreatedOn descending
select p)
.ToList();
Question: how would you write this LINQ expression using dot notation?

Like this:
List<Person> pr = db.Persons
.Join(db.PersonExceptions,
p => p.ID,
e => e.PersonID,
(p, e) => new { p, e })
.Where(z => z.e.CreatedOn >= fromDate)
.OrderByDescending(z => z.e.CreatedOn)
.Select(z => z.p)
.ToList();
Note how a new anonymous type is introduced to carry both the p and e bits forward. In the specification, query operators which do this use transparent identifiers to indicate the behaviour.

Related

Can I use OrderBy<T> to order by a Join<T> entity?

I need to translate a Linq query into Dynamic Linq but I'm having a problem with the OrderBy part.
This is the Linq query:
var q = from pp in ctx.MyEntity
join c in sortedListString on pp.CountryId.ToString() equals c.Substring(9)
orderby c ascending
select pp;
As you can see, I'm sorting by the entinty in the join.
Now I need to write the same query but with dynamic linq and I have:
var q = from pp in ctx.MyEntity
select pp;
q = q.Join(
sortedListString,
o => o.CountryId.ToString(),
i => i.Substring(9), (o, i) => o
).OrderBy(???);
What should I put in the OrderBy, knowing that I want to order by sortedListString?
Not sure what you mean by "dynamic linq" here, but equivalent of your query using "full" LINQ syntax is:
var q = ctx.MyEntity
.Join(sortedListString,
pp => pp.CountryId.ToString(),
c => c.Substring(9),
(pp, c) => new { pp, c })
.OrderBy(t => t.c)
.Select(t => t.pp);

Can make left join in Entity Framework without dataset

I have this query
return _ctx.TestPackages.Where(s => s.Id == TestPackageId).
Join(_ctx.TestPackageReportDetails, s => s.Id, d => d.TestPackageId, (s, d) => new { reportDetail = d, testpack = s }).
Join(_ctx.TestPackageReports, p => p.reportDetail.TestPackageReportId, o => o.Id, (p, o) => new { combined = p, report = o })
.ToList()
As you can see my query makes join between 3 tables TestPackages TestPackageReportDetails and TestPackageReports. When I have more than one record in TestPackageReportDetails with same testpackageid, the result is repeated 3 times in the output. How can I avoid the repetition?
Should I make a left join between TestPackageReportDetails and TestPackages? If yes how can I do that?
If your intention is to Eager load the report details then you should be using .Include :
_ctx.TestPackages.Include(t=>t.TestPackageReportDetails.TestPackageReports).Where(s => s.Id == TestPackageId);
Since you're only selecting three fields (As shown before you edit your answer again and remove the select) then you can do this:
(from s in _ctx.TestPackages
join d in _ctx.TestPackageReportDetails,
on s.Id equals d.TestPackageId
join r in _ctx.TestPackageReports
on s.Id equals r.reportDetail.TestPackageReportId
where s.Id == TestPackageId
select new
{
s.Id,
s.packageNumber,
s.Size,
s.TestPackageOrder
}).Distinct().ToList().Select(m=> new ..) // continue your normal selection

translating complex T-SQL query to LINQ to Entities

This is the SQL code the produces the correct results:
select s.Code, s.Name, coalesce(ss.Url, a.Url), a.SocialMediaTypeKey
from School s
Left join
(
SELECT dbo.SchoolSocialMedia.SocialMediaTypeKey
, SchoolSocialMedia.Url
, dbo.Department.Name
, dbo.Department.ImportBusinessKey
FROM dbo.SchoolSocialMedia
INNER JOIN dbo.Department ON dbo.SchoolSocialMedia.DepartmentId = dbo.Department.Id
) A
ON 1 = 1
Left join dbo.SchoolSocialMedia ss ON ss.SchoolId = s.Id and ss.SocialMediaTypeKey = a.SocialMediaTypeKey
where s.[DeactivatedDate] is null
This is how far I have gotten in C#, but it is not producing the correct results--in fact, it is returning zero results:
var departmentSocialMediaResult =
from ssm in context.SchoolSocialMedia
from d in context.Department.Where(d => d.Id == ssm.DepartmentId)
select new { ssm.SocialMediaTypeKey,
ssm.Url,
d.Name,
ssm.SchoolId };
var result =
(from s in context.School
from ssm in context.SchoolSocialMedia.DefaultIfEmpty()
from dssm in departmentSocialMediaResult.DefaultIfEmpty()
.Where(dssm => dssm.SchoolId == s.Id && dssm.SocialMediaTypeKey == ssm.SocialMediaTypeKey)
select new { ssm.SchoolId, ssm.SocialMediaTypeKey, ssm.Url })
.ToDictionary(ssm => new SchoolSocialMediaKey(
ssm.SchoolId, ssm.SocialMediaTypeKey),
ssm => ssm.Url);
Does anyone have any suggestions on how to better convert the T-SQL to LINQ to Entities? What am I doing wrong? TIA.
UPDATE:
Thank you, #Aducci, your response is the correct answer. Since the result is being put into a dictionary, this is what I ended up using:
var query =
(from s in context.School
from a in
(
from ssm in context.SchoolSocialMedia
join d in context.Department on ssm.DepartmentId equals d.Id
select new
{
ssm.SocialMediaTypeKey,
ssm.Url,
d.Name
}
).DefaultIfEmpty()
from ss in context.SchoolSocialMedia
.Where(x => s.Id == x.SchoolId)
.Where(x => a.SocialMediaTypeKey == x.SocialMediaTypeKey)
.DefaultIfEmpty()
select new
{
ss.SchoolId,
Url = ss.Url ?? a.Url,
a.SocialMediaTypeKey
}).Distinct();
return
query
.ToDictionary(
ssm => new SchoolSocialMediaKey(
ssm.SchoolId, ssm.SocialMediaTypeKey),
ssm => ssm.Url);
I am sure there is a better way to write the original query, but instead of spending too much time analyzing I just translated it into linq. In general, your linq query should have the same structure as the tsql query like this:
var query =
from s in context.School
from a in
(
from ssm in context.SchoolSocialMedia
join d in context.Department on ssm.DepartmentId equals d.Id
select new
{
ssm.SocialMediaTypeKey,
ssm.Url,
d.Name,
d.ImportBusinessKey
}
).DefaultIfEmpty()
from ss in context.SchoolSocialMedia
.Where(x => s.Id == x.SchoolId)
.Where(x => a.SocialMediaTypeKey == x.SocialMediaTypeKey)
.DefaultIfEmpty()
select new
{
s.Code,
s.Name,
Url = ss.Url ?? a.Url,
a.SocialMediaTypeKey
};

Converting a SQL Query to a Predicate Expression using Fluent Synatx

How do I write the following sql query to a Predicate Expression using Fluent Sytax:
select c.* from customer c
inner join Orders r on r.CustomerId = c.Id
where
c.MemberSince > '01/01/2013' &&
r.OrderDate > '01/01/2014'
order by r.OrderDate
I am expecting something like this:
Expression<Func<Customer, bool>> filters = PredicateBuilder.True<Customer>();
filters = filters.And(x => x.MemberSince > DateTime.Parse('01/01/2013'));
filterr = ....
I am not sure how to add the Orders predicate. And then I call:
var list = db.Customers.AsExpandable().Where(filters).ToList();
You don't need PredicateBuilder at all. You just need to understand that the result of a join is effectively a sequence of pairs:
DateTime memberCutoff = ...;
DateTime orderCutoff = ...;
var query = context.Customers
.Join(context.Orders,
c => c.Id, r => r.CustomerId, (c, r) => new { c, r })
.Where(pair => pair.c.MemberSince > memberCutoff &&
pair.r.OrderDate > orderCutoff)
.OrderBy(pair => pair.r.OrderDate);

Linq query syntax to method syntax when using multiple joins to introduce dynamic restrictions

I'm trying to translate a linq query using query keywords to the method syntax.
My ultimate goal is to be able to apply additonnal restrictions at runtime each time you see a Where clause in the query. I have a total of 14 different parameters to be applied. Some are mutually exclusive, other are inclusive.
Here is the starting query :
query = from p in context.Person
where p.Firstname.ToUpper().StartsWith(firstName.ToUpper())
join v in context.Visit on p.Id equals v.PersonId
where !v.AccessionNumber.StartsWith(RISConst.PM_PREFIX)
join f in context.Finding on v.Id equals f.VisitId
join c in context.Consultation on f.Id equals c.FindingId
where c.StudyId.ToUpper().CompareTo(studyId.ToUpper()) == 0
select v;
Using Jon Skeet's excellent blog post I have been able to go that far :
query = context.Person.Where(p => p.Firstname.ToUpper().StartsWith(firstName.ToUpper()))
.Join(context.Visit, p => p.Id, v => v.Id, (p, v) => new { p, v })
.Where(z => z.v.AccessionNumber.StartsWith(RISConst.PM_PREFIX))
.Select(z => z.v)
.Join(context.Finding, v => v.Id, f => f.VisitId, (v, f) => new { v, f })
.Select(t => t.f)
.Join(context.Consultation, f => f.Id, c => c.FindingId, (f, c) => new { f, c })
.Where( u => u.c.StudyId.ToUpper().CompareTo(studyId.ToUpper()) == 0)
.Select(????);
Now I'm stuck because I need to return Visits. How can I do that ?
Any Help appreciated.
I think you lost Visists on this select statement: .Select(t => t.f). Remove it and work with whole anonymous object on next statement.
.Join(context.Consultation, x => x.f.Id, c => c.FindingId, (x, c) => new { x.v, c })
.Where( u => u.c.StudyId.ToUpper().CompareTo(studyId.ToUpper()) == 0)
.Select(u => u.v);

Categories