i'm trying to join three caches with two of them are left outer joined,also has group by clause. With the below query i ran into strange issue, the generated sql was not correct.
var query = (from service in serviceCache
join meetingService in meetingServiceCache.DefaultIfEmpty() on service.Value.ServiceId equals meetingService.Value.ServiceId
join meeting in meetingCache.DefaultIfEmpty() on meetingService.Value.MeetingId equals meeting.Value.MeetingId
group new { service, meeting } by service.Value.ServiceId into g
select new {
service.Value.ServiceId,
lastMeeting = g.Select(x=>x.meeting.Value.CreatedDate).Max()
}).ToCacheQueryable().GetFieldsQuery.Sql;
The generated query looks like below
select _T0.SERVICEID,min(_T0.CreatedDate) from MEETINGSCHEMA.SERVICES as _T0
left outer join (select _T1.*,_T1.KEY,_T1.VAL from MEETINGSCHEMA.MEETINGSERVICE as _T1) as _T2 on (_T2.SERVICEID= _T0.SERVICEID)
left outer join (select _T3.*,_T3.KEY,_T3.VAL from MEETINGSCHEMA.MEETINGS as _T3) as _T4 on (_T4.MEETINGID= _T3.MEETINGID)
group by (_T0.SERVICEID)
In selected columns the createdDate should be selected from _T4 reference,But it's always selected from first table alias thus the query was failing always reporting CreatedDate as invalid column.I Suspect something wrong with linq to sql translation.
Please let me know if i'm doing any mistake. Also the code snippet was typed by hand with out intellisense, pardon me incase of typos.
After grouping you can select only Key property or aggregation functions. Also LEFT JOIN should be written in different way.
var query =
from service in serviceCache
join meetingService in meetingServiceCache on service.Value.ServiceId equals meetingService.Value.ServiceId into j
from meetingService in j.DefaultIfEmpty()
join meeting in meetingCache on meetingService.Value.MeetingId equals meeting.Value.MeetingId into j
from meeting in j.DefaultIfEmpty()
group new { service, meeting } by service.Value.ServiceId into g
select new
{
ServiceId = g.Key,
lastMeeting = g.Max(x => x.meeting.Value.CreatedDate)
};
This seems to be a bug in Ignite, I've filed a ticket.
The workaround is to reorder the joined tables and put meeting first, something like this:
var query = (from meeting in meetingCache
join meetingService in meetingServiceCache.DefaultIfEmpty() on meeting.Value.MeetingId equals meetingService.Value.MeetingId
join service in serviceCache service.Value.ServiceId equals meetingService.Value.ServiceId
group new { service, meeting } by service.Value.ServiceId into g
select new {
service.Value.ServiceId,
lastMeeting = g.Select(x=>x.meeting.Value.CreatedDate).Max()
}).ToCacheQueryable().GetFieldsQuery.Sql;
Another workaround is to use raw SQL for this query.
Related
I am not trying to join my table using left outer join in LINQ where one of my join conditions does not satisfy. How can I still get the default record in my dataset? My SQL query runs perfectly fine but my join query is not returning the data.
Below is my SQL query where my left outer join works fine:
select
w.issueid as Issue
from worklog w
join jiraissue as j on w.issueid=j.ID
join issuetype AS ty ON ty.ID = j.issuetype
join project AS p on p.ID=j.PROJECT
left outer join customfieldvalue cfv on cfv.ISSUE = w.issueid
Below is my LINQ query in C# where if cfv.issue in the last join is not available in the table, I want to still return the default column.
var data = (from w in worklogs
join i in issuetypes on j.issuetype equals i.ID
join p in projects on j.PROJECT equals p.ID into table0
from c in table0.DefaultIfEmpty()
join cfv in customfieldvalues on w.issueid equals cfv.ISSUE into table1
from d in table1.DefaultIfEmpty()
{
IssueKey = l.Key.pkey + '-' + l.Key.issuenum,
Hours = l.Sum(w => w.timeworked)
}).ToList();
Any help is appreciated.
Thank you.
I have this rather complex query in SQL server 2008:
declare #LanguageID as int = 1
select k.datePublish, k.dateEditing, k.dateTables
from TableAreasLevel1 as areaL1
inner join TableAreasLevel2 as areaL2
on areaL1.LanguageID = areaL2.LanguageID and
areaL1.CodeAreaLevel1 = areaL2.CodeAreaLevel1
inner join TableAreasLink as link
on areaL2.CodeAreaLevel1 = link.CodeAreaLevel1 and
areaL2.CodeAreaLevel2 = link.CodeAreaLevel2 and
inner join TableProducts as tblProds
on tblProds.CodeAreaLevel1 = areaL1.CodeAreaLevel1 and
tblProds.CodeAreaLevel2 = areaL2.CodeAreaLevel2
inner join TableSI_Products as prod
on prod.SiAreaCode = link.SiAreaCode
inner join TableCalendar as k
on k.KodTableSI_Products = tblProds.KodTableSI_Products
where areaL1.LanguageID = #LanguageID and
prod.Code = 'some string' and
k.LanguageID = #LanguageID and
tblProds.LanguageID = #LanguageID;
I am trying to develop the same query in LINQ, but I get error when I try join the table TableProducts, i.e the third consecutive join.
Here is my LINQ query:
List<Tuple<DateTime, DateTime, DateTime>> dates = (from areaL1 in gpe.TableAreasLevel1
join areaL2 in gpe.TableAreasLevel2
on new { areaL1.CodeAreaLevel1, areaL1.LanguageID } equals
new { areaL2.CodeAreaLevel1, areaL2.LanguageID }
join link in gpe.TableAreasLink
on new { areaL2.CodeAreaLevel1, areaL2.CodeAreaLevel2, areaL2.RbrOblastNivo2} equals
new {link.CodeAreaLevel1, link.CodeAreaLevel2}
join tblProds in gpe.TableProducts
on tblProds. // The name tblProds is not in the scope of the left side of 'equals'
);
Is the problem connected with how the tables are designed or, something else I should check for?
Any ideas, why tblProds is not visible in the scope of the LINQ query?
You are using Query as your guide something like:
on k.KodTableSI_Products = tblProds.KodTableSI_Products
but take a look at your linq:
on new { areaL1.CodeAreaLevel1, areaL1.LanguageID } equals
it has two fields. I think its not a good idea.
linq join something like
var dates = (from areaL1 in gpe.TableAreasLevel1
join areaL2 in gpe.TableAreasLevel2
on areaL1.PKFields equals areaL2.PKFields
where areaL1.CodeAreaLevel1== areaL2.CodeAreaLevel1 && areaL1.LanguageID = areaL2.LanguageID
Select new YournewClass{YournewClass.Field1=areaL1.fields1, And so on}
)
You can do to join the other tables with aliases.
Sorry need to go for now.
I'm giving you an idea.
Hope it helps.
I have a SQL query which includes a left join and a group by- so far so good- my trouble arises from one of the join conditions not being a straight "equals to" and I'm lost where to go with LINQ.
I know multiple join conditions usually involves creating a couple of anonymous objects and comparing them, but when I add an "equal to" and "a greater" than into the mix, I've no idea how that applies.
Here's what I'd like the query to look like if I had invented LINQ, but I know the "and" in my join condition is invalid;
var query =
from csp in db.ChatSessionPersons
join cm in db.ChatMessages on
csp.ChatSessionId equals cm.ChatSessionId
and cm.Id > csp.LastReadChatMessageId
// (i know these should be the other way round,
// but for readability I present them like this!)
into j1
from j2 in j1.DefaultIfEmpty()
group j2 by csp.ChatSessionId into grouped
select new {
ChatSessionId = grouped.Key,
UnreadCount = grouped.Count(t => t.Id != null)};
Any ideas anyone?
You can convert the non-equality condition to a lambda Where on the group join result.
var query = from csp in db.ChatSessionPersons
join cm in db.ChatMessages on csp.ChatSessionId equals cm.ChatSessionId into cmj
select new {
ChatSessionId = csp.ChatSessionId,
UnreadCount = cmj.Where(cm => cm.Id > csp.LastReadChatMessageId).Count()
};
NOTE: I modified the query a bit to remove the group by which isn't needed if you are using a group join that has already grouped the matching results, and to remove the left join DefaultIfEmpty which also isn't needed when processing a group join with something like Count, unless you wanted to return an UnreadCount of 1 when there are no matches, in which case you should put DefaultIfEmpty() before Count().
Of course, you could use query comprehension in the sub-query:
var query = from csp in db.ChatSessionPersons
join cm in db.ChatMessages on csp.ChatSessionId equals cm.ChatSessionId into cmj
select new {
ChatSessionId = csp.ChatSessionId,
UnreadCount = (from cm in cmj where cm.Id > csp.LastReadChatMessageId select cm).Count()
};
I am building a LINQ query, which will have comparisons attached to the 'where' section (the number of these comparisons depends on the user's selections).
In the code-behind, I want something like this:
var builtQuery =
from q in dc.Leads
join sr in dc.SalesReps on q.SalesRepID equals sr.SalesRepID
join co in dc.Companies on q.CompanyID equals co.CompanyID
join or in dc.Origins on q.OriginID equals or.OriginID
join pr in dc.Products on q.ProductID equals pr.ProductID
where
Here, in between the 'from' and 'select' parts, I will add a number of comparisons (depending on the user's selection of checkboxes).
And Finally:
select new { q.Ref, sr.Rep, q.Deposit, q.Sale, q.Title, q.Names, q.Surname, q.HomePhone, q.WorkPhone, q.Mobile, q.Address, q.Suburb, q.County, q.Postcode, co.CompanyName, or.OriginName, pr.ProductName, q.Telemarket, q.Entered };
In PHP (using MySQL) I could simply concatenate a number of strings, which make up the query. But, in c#/LINQ To SQL, the query is not a string and so I have no idea how to do this...There were a couple similar questions on SO, but they're not quite the same thing.
Any ideas??
Thanks!
I would do it in the following way
var intermediateQuery=
from q in dc.Leads
join sr in dc.SalesReps on q.SalesRepID equals sr.SalesRepID
join co in dc.Companies on q.CompanyID equals co.CompanyID
join or in dc.Origins on q.OriginID equals or.OriginID
join pr in dc.Products on q.ProductID equals pr.ProductID
select new { q.Ref, sr.Rep, q.Deposit, q.Sale, q.Title, q.Names, q.Surname, q.HomePhone, q.WorkPhone, q.Mobile, q.Address, q.Suburb, q.County, q.Postcode, co.CompanyName, or.OriginName, pr.ProductName, q.Telemarket, q.Entered };
and then add some filters considering user input
if(SomeUserProductFilter)
{
var result = intermediateQuery.Where(p=>p.ProductName = 'UserProductName');
}
Do not be afraid that this approach will retrieve all data and than filters it in memory. LINQ sends query to database only when you call ToList(), ToArray() or use result in foreach loop
This is a two part question and for education purposes rather than trying to find a solution to a problem.
I've seen this already and realize that it's very similar to my question
LINQ2SQL - Cross join emitted when I want inner join
But I am hoping for more information from you LINQ and SQL gurus as to why the cross join is created instead of inner join in LINQ2SQL. Additionally, can someone explain how SQL Server decides on the execution plan (or link to further information) since both of these queries generate the same plan? From what I understand, this means that the performance of the queries are the same.
I've created a small example that runs two LINQ expressions on my database that generates these two different SQL queries.
For those who don't want to bother, here's my example db diagram:
http://dl.dropbox.com/u/13256/Screen%20shot%202011-03-16%20at%2011.41.56%20AM.png
Here are the two queries:
Cross Join with Where Clause
var q = from item in context.Items
join i_mem in context.Memberships on new { item_id = item.ID, user_id =
current_user_id.Value } equals new { item_id = i_mem.RelatedItemID, user_id =
i_mem.RelatedUserID } into sq_i_m
from im in sq_i_m.DefaultIfEmpty()
join i_cat in context.Categories on item.RelatedCategoryID equals i_cat.ID
into sq_i_cat
from proj in sq_i_cat
select item;
Inner Join
from item in context.Items
join i_mem in context.Memberships on
new { item_id = item.ID, user_id = current_user_id.Value }
equals
new { item_id = i_mem.RelatedItemID, user_id = i_mem.RelatedUserID }
into sq_i_m
from im in sq_i_m.DefaultIfEmpty()
join i_cat in context.Categories on item.RelatedCategoryID equals i_cat.ID
select item
And here is the test program if you'd like to see for yourself.
Thanks for everyone's help.
Mustafa
They are the same thing, so it does not matter which LINQ2SQL emits.
An inner join is logically equivalent to a cross join with a where clause filter equivalent to the on of the inner join clause.
That's why Sql Server generates the same query plan.
To be clear, the inner join:
Select f1
From T1 inner join T2 on T1.k = T2.k
where T1.f2 like 'X%'
Is the same as the cross join:
Select f1
From T1 cross join T2
where T1.k = T2.k
and T1.f2 like 'X%'
is the same as old-style SQL:
Select f1
From T1, T2
where T1.k = T2.k
and T1.f2 like 'X%'
Lets say you have a datacontext called MyDataContext.
using(MyDataContext db = new MyDataContext())
{
var q = db.Items.Where(x=> x.Categories.Name == "myCategory").Select(x=> x);
}
This is a very simple example, but you didn't need to write out a join or a subquery in TSQL syntax. (I hate writing TSQL).