LINQ:从左连接填充对象

Posted

技术标签:

【中文标题】LINQ:从左连接填充对象【英文标题】:LINQ: Fill objects from left join 【发布时间】:2012-09-19 14:24:48 【问题描述】:

我是 linq 的新手。如何使用 LINQ 从左连接数据库查询 (PostGIS) 加载我的对象。

这是我的数据库查询:

SELECT          
                dt.id, 
                dt.type, 
                dta.id as "AttId",
                dta.label,
                dtav.id as "AttValueId",
                dtav.value

FROM            public."dataTypes" dt, 
                public."dataTypeAttributes" dta
LEFT JOIN       public."dataTypeAttributeValues" dtav
ON              dta.id = "dataTypeAttributeId"        
WHERE           dt.id = dta."dataTypeId"
ORDER BY        dt.type, dta.label, dtav.value

这是示例输出:

我有 3 个实体:

public class TypeData

    public int ID  get; set; 
    public string Type  get; set; 
    public TypeDataAttribute[] Attributes  get; set; 


public class TypeDataAttribute

    public int ID  get; set; 
    public string Label  get; set; 
    public TypeDataAttributeValue[] Values  get; set; 


public class TypeDataAttributeValue

    public int ID  get; set; 
    public string Value  get; set; 

更新

这是我卡住的地方:

...
using (NpgsqlDataReader reader = command.ExecuteReader())


    if (reader.HasRows)
    
        IEnumerable<TypeData> typeData = reader.Cast<System.Data.Common.DbDataRecord>()
            .GroupJoin( //<--stuck here.
    
...

解决方案:

使用 AmyB 的回答,这就是我的对象:

using (NpgsqlDataReader reader = command.ExecuteReader())


    if (reader.HasRows)
    

        var groups = reader.Cast<System.Data.Common.DbDataRecord>()
            .GroupBy(dr => new  ID = (int)dr["id"], AttID = (int)dr["AttId"] )
            .GroupBy(g => g.Key.ID);

        typeDataList = (
            from typeGroup in groups
            let typeRow = typeGroup.First().First()
            select new TypeData()
            
                ID = (int) typeRow["id"],
                Type = (string) typeRow["type"],
                Attributes = 
                (
                    from attGroup in typeGroup
                    let attRow = attGroup.First()
                    select new TypeDataAttribute()
                    
                        ID = (int)attRow["AttId"],
                        Label = (string)attRow["label"],
                        PossibleValues =
                        (
                            from row in attGroup
                            where !DBNull.Value.Equals(attRow["AttValueId"])
                            select new TypeDataAttributeValue()  ID = (int)row["AttValueId"], Value = (string)row["value"] 
                        ).ToArray()
                    
                ).ToArray()
            
        );
    

【问题讨论】:

@AmyB IEnumerable&lt;TypeData&gt; typeData = reader.Cast&lt;System.Data.Common.DbDataRecord&gt;().GroupJoin... 我被困在这里了。 【参考方案1】:

所以 - 如果我理解正确 - 您有一个满意的数据库查询,但您想要获取行列形状的结果并将其投影到分层形状的结果中。


假设结果在List&lt;Row&gt;

public class Row

  public int id get;set;
  public string type get;set;
  public int attid get;set;
  public string label get;set;
  public int? attvalueid get;set;
  public string value get;set;

然后你会分组两次,将每个***组变成一个Type,每个子级组变成一个Attribute,每一行变成一个Value(如果该行不是空值) .

List<Row> queryResult = GetQueryResult();

//make our hierarchies.
var groups = queryResult
  .GroupBy(row => new row.id, row.attid)
  .GroupBy(g => g.Key.id);

//now shape each level
List<Type> answer =
(
  from typeGroup in groups
  let typeRow = typeGroup.First().First()
  select new Type()
  
    id = typeRow.id,
    type = typeRow.type,
    Attributes =
    (
      from attGroup in typeGroup
      let attRow = attGroup.First()
      select new Attribute()
      
        id = attRow.attid,
        label = attRow.label
        Values =
        (
          from row in attRow
          where row.attvalueid.HasValue  //if no values, then we get an empty array
          select new Value() id = row.attvalueid, value = row.value 
        ).ToArray()
      
    ).ToArray()
  
).ToList();

【讨论】:

我相信这就是我想要的......可能需要我一点时间来消化和尝试。非常感谢! 效果很棒,除了一件事......在最里面嵌套的Values = ( from row... 我得到的值的数量是正确的,但它们都是相同的值。例如,我得到两个“升序”值,而不是一个“升序”和一个“降序”。我能做些什么来解决这个问题? 没关系...我错了..这是我的错误。为了表示感谢,我通过在your profile answers page.@ 的第一页上为您正确回答的每个答案点赞,奖励您超过 160 分 @capdragon - 请根据他们的个人优点对答案进行投票,而不是作为对其他行为的奖励 - 所有这些投票都被检测为系统“游戏”并且代表被撤销。如果您想更多地奖励特定答案 - 方法是添加和奖励赏金。 (+1...再次)感谢您告诉我。赏金的东西是“不受我控制”的,别人可以拿错答案但得到大众的支持,你要等很多天。或者可能有一个错误的答案,他们得到了赏金。这是一个巨大的浪费IMO。应该有一种更好的方式来奖励那些超越自我的人的声誉。我想我可以做到,不那么明显;)【参考方案2】:
 var q = (from dt in public."dataTypes"
         // Join the second table to the first, using the IDs of the two tables <-- You may join on different columns from the two tables
         join dta in public."dataTypeAttributes" on
         new  ID = dt.id  equals
         new  ID = dta.id 
         // Join the third table to the first, using the IDs of the two tables
         join dtav in public."dataTypeAttributeId" on
         new  ID = dt.id  equals
         new  ID = dtav.id 
         // Conditional statement
         where dt.id == dta."dataTypeId"
         // Order the results
         orderby dt.type, dta.label, dtav.value
         // Select the values into a new object (datObj is a created class with the below variables)
         select new datObj() 
            ID = dt.id,
            Type = dt.type,
            AttID = dta.id,
            Label = dta.label,
            AttValueID = dtav.id,
            AttValue = dtav.value
         ).ToList()

这将按照orderby 语句指定的顺序返回与您的where 语句匹配的列表。

不完全是你需要的,但应该给你一个你应该做什么的例子。

【讨论】:

@capdragon 它可能与您正在寻找的内容有点不同,但它应该让您知道要寻找什么。【参考方案3】:

试试GroupJoinsytnax

还有Join 用于常规内连接的语法

这个link有一个加入群组的例子

【讨论】:

我想这就是我要找的。 (+1)【参考方案4】:

Yopu 应该检查一下:http://codingsense.wordpress.com/2009/03/08/left-join-right-join-using-linq/

【讨论】:

我查看了许多教程和链接,例如您提供的那个,但我不明白。您能否通过填充我的实体而不是 console.write 来展示这将如何应用于我的代码?

以上是关于LINQ:从左连接填充对象的主要内容,如果未能解决你的问题,请参考以下文章

Linq:选择不同的对象左连接

在 linq 的 join 命令中获取左连接对象

Linq 和 SQL的左连接右连接内链接

LINQ的左连接右连接内连接

LINQ的左连接右连接内连接

LINQ的左连接右连接内连接