public class Question { public virtual int QuestionId { get; set; } public virtual string Text { get; set; } public virtual string Poster { get; set; } public virtual IList<QuestionComment> Comments { get; set; } public virtual IList<Answer> Answers{ get; set; } public virtual byte[] RowVersion { get; set; } } public class QuestionComment { public virtual Question Question { get; set; } public virtual int QuestionCommentId { get; set; } public virtual string Text { get; set; } public virtual string Poster { get; set; } } public class Answer { public virtual Question Question { get; set; } public virtual int AnswerId { get; set; } public virtual string Text { get; set; } public virtual string Poster { get; set; } public virtual IList<AnswerComment> Comments { get; set; } } public class AnswerComment { public virtual Answer Answer { get; set; } public virtual int AnswerCommentId { get; set; } public virtual string Text { get; set; } public virtual string Poster { get; set; } }
This is the INNER JOIN using LINQ:
var www = from x in q.All from y in x.Answers group y by new { x.QuestionId } into grp select new { grp.Key.QuestionId, Count = grp.Count() };
Output by Entity Framework:
SELECT [GroupBy1].[K1] AS [Question_QuestionId], [GroupBy1].[A1] AS [C1] FROM ( SELECT [Extent1].[Question_QuestionId] AS [K1], COUNT(1) AS [A1] FROM [dbo].[Answer] AS [Extent1] GROUP BY [Extent1].[Question_QuestionId] ) AS [GroupBy1]
Output by NHibernate:
SELECT question0_.QuestionId AS col_0_0_, CAST(COUNT(*) AS INT) AS col_1_0_ FROM [Question] question0_ INNER JOIN [Answer] answers1_ ON question0_.QuestionId=answers1_.Question_QuestionId GROUP BY question0_.QuestionId
This is the LEFT JOIN using LINQ:
var www = from x in q.All from y in x.Answers.DefaultIfEmpty() group y by new { x.QuestionId } into grp select new { grp.Key.QuestionId, AnswersCount = grp.Count() };
This is Entity Framework output:
SELECT [GroupBy1].[K1] AS [QuestionId], [GroupBy1].[A1] AS [C1] FROM ( SELECT [Extent1].[QuestionId] AS [K1], COUNT(1) AS [A1] FROM [dbo].[Question] AS [Extent1] LEFT OUTER JOIN [dbo].[Answer] AS [Extent2] ON [Extent1].[QuestionId] = [Extent2].[Question_QuestionId] GROUP BY [Extent1].[QuestionId] ) AS [GroupBy1]
NHibernate is currently lacking LEFT JOIN
System.NotSupportedException: The DefaultIfEmptyResultOperator result operator is not current supported
But as any programmers worth their salt, they can quickly discern that the query is not a proper LEFT JOIN. A Question's AnswersCount will still have a value of 1 even there's no matching answers on a given question
It should be constructed this way:
var www = from x in q.All from y in x.Answers.DefaultIfEmpty() group y by new { x.QuestionId } into grp select new { grp.Key.QuestionId, Count = grp.Sum(x => x.Question.QuestionId != null ? 1 : 0 ) }; // similar to this: http://stackoverflow.com/questions/3789850/is-clean-sql-achievable-on-linq-to-sql
Entity Framework's Linq query generator is atrocious compared to other ORMs (even when compared to Linq-to-Sql):
SELECT [GroupBy1].[K1] AS [QuestionId], [GroupBy1].[A1] AS [C1] FROM ( SELECT [Join1].[K1] AS [K1], SUM([Join1].[A1]) AS [A1] FROM ( SELECT [Extent1].[QuestionId] AS [K1], CASE WHEN ([Extent2].[Question_QuestionId] IS NOT NULL) THEN 1 ELSE 0 END AS [A1] FROM [dbo].[Question] AS [Extent1] LEFT OUTER JOIN [dbo].[Answer] AS [Extent2] ON [Extent1].[QuestionId] = [Extent2].[Question_QuestionId] ) AS [Join1] GROUP BY [K1] ) AS [GroupBy1]
Contrast that with this Linq-to-Sql sample generated query (same scenario as above, i.e. using two tables too). This is very lean
SELECT SUM( (CASE WHEN [t1].[CustomerID] IS NOT NULL THEN @p0 ELSE @p1 END)) AS [N], [t0].[CustomerID] AS [Key] FROM [Customers] AS [t0] LEFT OUTER JOIN [Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID] GROUP BY [t0].[CustomerID] // source: http://stackoverflow.com/questions/3789850/is-clean-sql-achievable-on-linq-to-sql
For NHibernate, you have to use QueryOver for LEFT JOIN functionality: http://www.ienablemuch.com/2012/12/nhibernates-non-stringly-typed-left-join.html
No comments:
Post a Comment