简体   繁体   English

LINQ连接查询与关系实体

[英]LINQ join query with relational entities

I am using ef-core 2.1, I have the following simplified entities where one Account maps to zero or more Attribute objects: 我使用的是ef-core 2.1,我有以下简化实体,其中一个Account映射到零个或多个Attribute对象:

public class Account
{
    public int Id { get; set; }
    public int LongId { get; set; }
    public List<Attribute> Attributes { get; set; }
}

public class Attribute
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
    public Account Account { get; set; }
}

I have an initial collection of strings that resemble an Attribute.Value for a given fixed Attribute.Name , I want to find a second associated Attribute object from the same parent Account and obtain its Attribute.Value . 我有类似的字符串的初始集合Attribute.Value对于给定的固定Attribute.Name ,我想找到第二个相关的Attribute从相同的父对象Account ,并获得其Attribute.Value

I want to left join the ef entities against the initial string collection so I can easily infer: 我想在最初的字符串集合中加入ef实体,这样我就可以很容易地推断:

  1. Whether no corresponding Account exists or an Account exists without the related Attribute objects (both equate to the same use case). 是否存在相应的Account或没有相关Attribute对象的Account (两者都等同于相同的用例)。
  2. If an Account exists and it contains all the required Attribute objects, I want to obtain the value of the secondary Attribute . 如果存在一个Account并且它包含所有必需的Attribute对象,我想获取辅助Attribute的值。

Without LINQ and ef, I run the following SQL query which ignores the parent Account and produces the result set I want: 没有LINQ和ef,我运行以下SQL查询,忽略父Account并生成我想要的结果集:

CREATE TABLE #Temp
(
    id nvarchar(20) not null
);
INSERT INTO #Temp (id) VALUES ('cejawq'), ('issokq'), ('cqlpjq'), ('mbgzvi'), ('wqwlff'), ('iedifh');
SELECT t.[Id], attr2.[Value]
FROM #Temp t
LEFT OUTER JOIN [dbo].[Attributes] attr1
    ON t.[Id]=attr1.[Value]
    AND attr1.[Name]='uid'
LEFT OUTER JOIN [dbo].[Attributes] attr2
    ON attr1.[AccountId]=attr2.[AccountId]
    AND attr2.[Name]='objType';

I get the following result set: 我得到以下结果集:

id|objType
-----------
cejawq|ext
issokq|ext
cqlpjq|int
mbgzvi|int
wqwlff|ext
iedifh|null

I am struggling with mapping this to efficient LINQ such that the SQL generated produces the result set remotely and ships back data that I can project to an equivalent anonymous type. 我正在努力将其映射到高效的LINQ,以便生成的SQL远程生成结果集并将我可以投影的数据发送回等效的匿名类型。 Do I need to care about the parent objects in the LINQ case? 我是否需要关心LINQ案例中的父对象? I don't have an index on the Attribute.Value column. 我在Attribute.Value列上没有索引。

The Attributes table contains the following data: Attributes表包含以下数据:

Id|Name   |Value |AccountId
1 |uid    |cejawq|1
2 |objType|ext   |1
3 |uid    |issokq|2
4 |objType|ext   |2
5 |uid    |cqlpjq|3
6 |objType|int   |3
7 |uid    |mbgzvi|4
8 |objType|int   |4
9 |uid    |wqwlff|5
10|objType|ext   |5

Since the EF Core does not support joins with in memory sequences (yet), you can split the query in two parts - one which takes the data server side ( [Attributes to [Attributes join) using in memory collection as filter (SQL IN through LINQ Contains method), and second which performs left join in memory with the result of the db query: 由于EF Core不支持与内存序列(但尚未)的连接,您可以将查询拆分为两部分 - 一部分采用数据服务器端( [Attributes[Attributes连接],使用内存集合作为过滤器(SQL IN through LINQ Contains方法),第二个使用db查询的结果在内存中执行左连接:

DbContext db = ...;
var uids = new [] { "cejawq", "issokq", "cqlpjq", "mbgzvi", "wqwlff", "iedifh" };

var dbQuery =
    from attr1 in db.Set<Attribute>()
    where attr1.Name == "uid" && uids.Contains(attr1.Value)
    join attr2 in db.Set<Attribute>()
    on new { AccountId = attr1.Account.Id, Name = "objType" }
    equals new { AccountId = attr2.Account.Id, attr2.Name }
    into attr2Group from attr2 in attr2Group.DefaultIfEmpty() // left outer join
    select new { uid = attr1.Value, objType = attr2.Value };

var query =
    from uid in uids
    join dbResult in dbQuery on uid equals dbResult.uid
    into dbResultGroup from dbResult in dbResultGroup.DefaultIfEmpty() // left outer join
    select new { uid, dbResult?.objType };

var result = query.ToList();

It translates to a single db query like this: 它转换为单个数据库查询,如下所示:

SELECT [attr1].[Value] AS [uid], [attr2].[Value] AS [objType]
FROM [Attributes] AS [attr1]
LEFT JOIN [Attributes] AS [attr2] ON ([attr1].[AccountId] = [attr2].[AccountId]) AND (N'objType' = [attr2].[Name])
WHERE ([attr1].[Name] = N'uid') AND [attr1].[Value] IN (N'cejawq', N'issokq', N'cqlpjq', N'mbgzvi', N'wqwlff', N'iedifh')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM