6

我正在使用以下 SQL 查询:

SELECT 
a.AppointmentId,
a.Status,
a.Type,
a.Title,
b.Days,
d.Description,
e.FormId
FROM Appointment a (nolock)
LEFT JOIN AppointmentFormula b (nolock)
ON a.AppointmentId = b.AppointmentId and b.RowStatus = 1
JOIN Type d (nolock)
ON a.Type = d.TypeId
LEFT JOIN AppointmentForm e (nolock)
ON e.AppointmentId = a.AppointmentId
WHERE a.RowStatus = 1
AND a.Type = 1
ORDER BY a.Type

我不确定如何在 LINQ 中实现 JOIN。我所有的表都有外键关系。

4

3 回答 3

29
SELECT A.X, B.Y
FROM A JOIN B ON A.X = B.Y

这个 linq 方法调用(to Join)会生成上面的 Join。

var query = A.Join
(
  B,
  a => a.x,
  b => b.y,
  (a, b) => new {a.x, b.y} //if you want more columns - add them here.
);

SELECT A.X, B.Y
FROM A LEFT JOIN B ON A.X = B.Y

These linq method calls (to GroupJoin, SelectMany, DefaultIfEmpty) will produce the above Left Join

var query = A.GroupJoin
(
  B,
  a => a.x,
  b => b.y,
  (a, g) => new {a, g}
).SelectMany
(
  z => z.g.DefaultIfEmpty(),
  (z, b) =>
    new  { x = z.a.x, y = b.y } //if you want more columns - add them here.
);

The key concept here is that Linq's methods produce hierarchically shaped results, not flattened row-column shapes.

  • Linq's GroupBy produces results shaped in a hierarchy with a grouping key matched to a collection of elements (which may not be empty). SQL's GroupBy clause produces a grouping key with aggregated values - there is no sub-collection to work with.
  • Similarly, Linq's GroupJoin produces a hierarchical shape - a parent record matched to a collection of child records (which may be empty). Sql's LEFT JOIN produces a parent record matched to each child record, or a null child record if there are no other matches. To get to Sql's shape from Linq's shape, one must unpack the collection of child records with SelectMany - and deal with empty collections of child records using DefaultIfEmpty.

And here's my attempt at linquifying that sql in the question:

var query =
  from a in Appointment
  where a.RowStatus == 1
  where a.Type == 1
  from b in a.AppointmentFormula.Where(af => af.RowStatus == 1).DefaultIfEmpty()
  from d in a.TypeRecord //a has a type column and is related to a table named type, disambiguate the names
  from e in a.AppointmentForm.DefaultIfEmpty()
  order by a.Type
  select new { a.AppointmentId, a.Status, a.Type, a.Title, b.Days, d.Description, e.Form }
于 2009-06-19T04:30:56.953 回答
5

你可能需要稍微调整一下,因为我正在袖手旁观,但有几件重要的事情要记住。如果您在 dbml 中正确设置了关系,您应该能够隐式地进行内部连接,并且只需通过初始表访问数据。此外,LINQ 中的左连接并不像我们希望的那样直接,您必须通过 DefaultIfEmpty 语法才能实现它。我在这里创建了一个匿名类型,但您可能想要放入 DTO 类或类似的东西。我也不知道你想在 null 的情况下做什么,但你可以使用 ?? 语法来定义一个值以在值为 null 时给出变量。如果您还有其他问题,请告诉我...

var query = (from a in context.Appointment
join b in context.AppointmentFormula on a.AppointmentId equals b.AppointmentId into temp
from c in temp.DefaultIfEmpty()
join d in context.AppointmentForm on a.AppointmentID equals e.AppointmentID into temp2
from e in temp2.DefaultIfEmpty()
where a.RowStatus == 1 && c.RowStatus == 1 && a.Type == 1
select new {a.AppointmentId, a.Status, a.Type, a.Title, c.Days ?? 0, a.Type.Description, e.FormID ?? 0}).OrderBy(a.Type);
于 2009-06-18T14:59:33.257 回答
1

If you want to preserve the (NOLOCK) hints, I have blogged a handy solution using extension methods in C#. Note that this is the same as adding nolock hints to every table in the query.

于 2010-06-09T01:40:54.740 回答