代码之家  ›  专栏  ›  技术社区  ›  Ritmo2k

具有关系实体的LINQ连接查询

  •  4
  • Ritmo2k  · 技术社区  · 6 年前

    我使用的是efcore2.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; }
    }
    

    我有一个类似于 Attribute.Value Attribute.Name ,我想找第二个 属性 帐户 并获得 属性值 .

    1. 是否无对应 帐户 存在或 帐户 属性 对象(两者等同于相同的用例)。
    2. 如果 帐户 存在并包含所有必需的 属性 属性 .

    帐户

    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';
    

    我得到以下结果集:

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

    我正在努力将其映射到高效的LINQ,以便生成的SQL远程生成结果集,并返回可以投影到等效匿名类型的数据。我需要关心LINQ案例中的父对象吗?我在地图上没有索引 列。

    这个 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
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Ivan Stoev    6 年前

    由于EF Core不支持与内存序列的连接(现在),因此可以将查询分为两部分—一部分是数据服务器端( [Attributes [属性 IN 通过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();
    

    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')