Using Linq Join within the Where clause of another Linq Query - c#

I want to have Linq Query as below, but the not able to, its giving me compile time error any help please? The error is "inference failed to call the Join" - any help please? I want to use join within where clause of other query, is that possible?
Case _case = (from x in this.Context().CaseRepository.GetAll()
where (from g in x.Violations
join a in this.Context().OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Violation")
on new { g.ViolationId, this.NOVId } equals new { a.ChildEntityId, a.ParentId }
where g.CaseId == x.CaseId
select g).Count() > 0
select x).FirstOrDefault();
this.TriggerMetaDataUpdate<Case>(_case);
this.TriggerMetaDataUpdate<InspectionResult>(this.InspectionResult);

I did it in the following way:
var Violations = (from v in UnitOfWork.ViolationRepository.GetAll()
join a in UnitOfWork.OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Violation")
on v.ViolationId equals a.ChildEntityId
join b in UnitOfWork.OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Case")
on a.ParentId equals b.ParentId
where b.ChildEntityId == caseId
orderby v.ViolationId
select v).ToList();

Related

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

Filtering the result set of a LINQ query

I have the following LINQ query that works fine:
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
Now I want the query to only return those records where FieldValue equals to the value submitted from TextBox1
I have tried:
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
and
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
comps=comps.Where(x => x.FieldValue== TextBox1);
return View(comps);
But neither returns any data. What am I doing wrong?
Update:
public ActionResult Index(string TextBox1)
{
if (TextBox1 != null)
{
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
}
}
SOLVED! Answer is below! Not what I thought - reversing the table order in the query worked. Interesting pafr is that the query without a filter worked regardless of table order
The problem might be with what you think you are doing and what you actually do
You see as with most programing languages, in C# String is not value type but object, and the thing you are doing is actually comparing two adresses so to put it simply you check if the object in textBox1 is the same object you have as r.FildValue and what you really what to do is checking its contents, in C# each objeact has method Equals for comparing to other.
Try
where TextBox1.Equals(r.FieldValue)
The other think that you should check is if TextBox1 is value is correct
You can use System.Diagnostic.Debug.WriteLine("MyText" + TextBox1); to do that
Cheers :)
Hmmm, very strange. I was able to resolve the issue by switching the table order. Strangely the LINQ query worked fine when there was no filter but once filter was added - nothing. So I reversed the order of the tables and instead of
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
used:
var comps = (from r in tc.registry
join c in tc.companies
on r.Key equals c.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
and it worked like a charm!

Querying within other result query with linq

I'm getting a problem with a query with linq in EF.
Basically, what i'm tring to do is this, in plain SQL:
SELECT
t2.*
FROM
[SHP_Console2].[dbo].[Domain] t1
INNER JOIN
[SHP_Console2].[dbo].[Domain] t2
ON t2.[left] >=t1.[left] AND t2.[right]<=t1.[right]
WHERE
t1.ID =1
I'm not able to do this with linq.
I'm tring this:
from a in DomainRep.Where(c => c.ID == domainID).Select(c => new { c.left, c.right })
from b in DomainRep.Where(x => x.left >= a.left && x.right <= a.right)
select a;
What i'm doing wrong?
You mixed your query with anonymous types. You can't do that this way.
You also can't use JOIN with >= condition - LINQ does not support that kind of statements. However, it can be done using alternative syntax.
from a in DomainRep
from b in DomainRep
where b.left >= 1.left && b.right <= a.right && a.ID = 1
select b;
Edit: Reference: http://social.msdn.microsoft.com/Forums/en-US/linqprojectgeneral/thread/428c9db2-29f6-45d8-ab97-f00282397368/
var query = (from a in DomainRep
from b in DomainRep
where a.left >= b.left
select b)
.ToList();

Why ".Distinct() " doesn't work as expected [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
DISTINCT() and ORDERBY issue
listOrders.DataSource = (from sp in dbdata.Specifications.Where(i => i.Approve == "Yes" && i.Awailable_BOM == "Yes")
join ord in dbdata.Orders on sp.O_id equals ord.O_id
join prd in dbdata.Products.Where(k => k.Hours_prd == null) on ord.O_id equals prd.O_ID
orderby ord.Special, sp.Due_date
select ord.O_id).Distinct();
I am tring to order by "ord.Special, sp.Due_date" but it doesn't work after I put "Distinct();". So how do I order by "ord.Special, sp.Due_date" and get distinct values.
I think this will return ordered ids:
listOrders.DataSource =
from sp in dbdata.Specifications.Where(i => i.Approve == "Yes" && i.Awailable_BOM == "Yes")
join ord in dbdata.Orders on sp.O_id equals ord.O_id
join prd in dbdata.Products.Where(k => k.Hours_prd == null) on ord.O_id equals prd.O_ID
select new { ord.Special, sp.Due_date, ord.O_id } into x
group x by x.O_id into g
select new { g.Key, X = g.OrderBy(i => i.Special).ThenBy(i => i.Due_date).First()) } into y
orderby y.X.Special, y.X.Due_date
select y.Key;
Comments:
select only fields you are interested in into x
group those fields by field you want to be distinct into group g
from each group select key (ord.O_id) and group item X, which will define order of id in result (in this case First occurrence of id will be returned)
order results by X
select Key (ord.O_id)

Creating a dynamic linq query

I have the following query:
from p in dataContext.Repository<IPerson>()
join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
join spp2 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp2.PersonId
join s2 in dataContext.Repository<ISports>() on spp2.SportsId equals s2.Id
where s1.Name == "Soccer" && s2.Name == "Tennis"
select new { p.Id };
It selects all the person who play Soccer and Tennis.
On runtime the user can select other tags to add to the query, for instance: "Hockey". now my question is, how could I dynamically add "Hockey" to the query? If "Hockey" is added to the query, it would look like this:
from p in dataContext.Repository<IPerson>()
join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
join spp2 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp2.PersonId
join s2 in dataContext.Repository<ISports>() on spp2.SportsId equals s2.Id
join spp3 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp3.PersonId
join s3 in dataContext.Repository<ISports>() on spp3.SportsId equals s3.Id
where s1.Name == "Soccer" && s2.Name == "Tennis" && s3.Name == "Hockey"
select new { p.Id };
It would be preferable if the query is build up dynamically like:
private void queryTagBuilder(List<string> tags)
{
IDataContext dataContext = new LinqToSqlContext(new L2S.DataContext());
foreach(string tag in tags)
{
//Build the query?
}
}
Anyone has an idea on how to set this up correctly?
Thanks in advance!
A LINQ query is not parsed until it is actually executed. So you can do stuff like this:
var q = from r in ctx.records
/* Do other stuff */
select r;
if (!string.IsNullOrEmpty(search)) {
q = from r in q
where r.title == search
select r;
}
if (orderByName) {
q = q.OrderBy(r => r.name);
}
/* etc */
this will create one SQL statement being executed.
For your specific question: The joins make it somewhat complicated, but I think you can join with other "dynamic" queries.
So you would end up with something like this:
var baseQ = from p in dataContext.Repository<IPerson>()
select p;
foreach(var tag in tags) {
baseQ = from p in baseQ
join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
where s1.name == tag
select p;
}
/* If you have defined your relations correct, simplify to something like this.
Does not actually work because of SportsPerPerson probably has multiple sports: */
foreach(var tag in tags) {
baseQ = baseQ.Any(p => p.SportsPerPerson.Sports.Name == tag);
}
var resultQ = from p in baseQ
select new { p.Id };
Me and my colleague have found the solution, and we refactored the query so it would work properly. We now use the following query to retrieve the correct resultset:
var query = dataContext.Repository<ILead>();
foreach (var tag in tags)
{
String tagName = tag;
query = query.Where(l => dataContext.Repository<ISportsPerPerson>()
.Any(tpl => tpl.PersonId.Equals(l.Id) && tpl.Sports.Name.Equals(tagName)));
}
// Do something with query resultset :]

Categories