LINQ 中的 JOIN 和 LEFT JOIN 等效项

发布于 2024-07-25 02:32:48 字数 472 浏览 4 评论 0原文

我正在使用以下 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。 我的所有表都有外键关系。

I am working with the following SQL query:

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

I am unsure how to achieve the JOINs in LINQ. All my tables have foreign key relationships.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱人如己 2024-08-01 02:32:48
SELECT A.X, B.Y
FROM A JOIN B ON A.X = B.Y

此 linq 方法调用(对 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

这些 linq 方法调用(对 GroupJoin、SelectMany、DefaultIfEmpty)将生成上述 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.
);

这里的关键概念是 Linq 的方法生成分层形状的结果,而不是展平的行列形状。

  • Linq 的 GroupBy 生成层次结构中的结果,其分组键与元素的集合(可能不为空)相匹配。 SQL 的 GroupBy 子句生成带有聚合值的分组键 - 没有可以使用的子集合。
  • 类似地,Linq 的 GroupJoin 会生成一个分层形状 - 父记录与子记录的集合(可能为空)相匹配。 Sql 的 LEFT JOIN 生成与每个子记录匹配的父记录,如果没有其他匹配,则生成空子记录。 要从 Linq 的形状获取 Sql 的形状,必须使用 SelectMany 解压子记录集合 - 并使用 DefaultIfEmpty 处理空的子记录集合。

这是我尝试对问题中的 sql 进行解析:

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 }
SELECT A.X, B.Y
FROM A JOIN B ON A.X = B.Y

This linq method call (to Join) will generate the above 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 }
掩饰不了的爱 2024-08-01 02:32:48

当我即兴发言时,您可能需要稍微调整一下,但有几件重要的事情需要记住。 如果您在 dbml 中正确设置了关系,那么您应该能够隐式执行内部联接,并且只需通过初始表访问数据。 另外,LINQ 中的左连接并不像我们希望的那么简单,您必须通过 DefaultIfEmpty 语法才能实现它。 我在这里创建了一个匿名类型,但您可能希望将其放入 DTO 类或类似的东西中。 我也不知道在空值的情况下你想做什么,但你可以使用 ?? 语法来定义一个值,如果该值为 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);

You may have to tweak this slightly as I was going off the cuff, but there are a couple of major things to keep in mind. If you have your relationships set up properly in your dbml, you should be able to do inner joins implicitly and just access the data through your initial table. Also, left joins in LINQ are not as straight forward as we may hope and you have to go through the DefaultIfEmpty syntax in order to make it happen. I created an anonymous type here, but you may want to put into a DTO class or something to that effect. I also didn't know what you wanted to do in the case of nulls, but you can use the ?? syntax to define a value to give the variable if the value is null. Let me know if you have additional questions...

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);
北座城市 2024-08-01 02:32:48

如果您想保留(NOLOCK)提示,我有 在博客中发布了一个使用 C# 扩展方法的便捷解决方案。 请注意,这与向查询中的每个表添加 nolock 提示相同。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文