【问题标题】:How to retrieve all columns from table1 and matching columns from table2(Left outer join) using Linq如何使用 Linq 检索 table1 中的所有列和 table2 中的匹配列(左外连接)
【发布时间】:2015-08-17 16:10:37
【问题描述】:

我必须从 table1 中检索所有列并从 table2 中检索匹配列。我有一个存储过程:

alter  Procedure [dbo].[usp_Property]
@UserId bigint =null
As
Begin
select P.PID, P.PropertyName, P.SBUArea, P.ListedOn, 
       P.Availability, P.Price,   F.UserID, F.PID as FavProjId  
       from dbo.Property P left outer join dbo.Favorite F
       on (F.PID=P.PID And F.UserID=@UserId)

我想获得相同的 Linq 查询。到目前为止,我尝试过类似

//User Id comes from session..
//var userId
var result=(from p in Properties
                   join f in Favorites
                   on p.PID equals f.PID into r
                   from r1 in r.DefaultIfEmpty()
                   where r1.UserID==userId
                   select new
                   {
                     p.PID,
                      p.PropertyName,                       
                      p.SBUArea, p.ListedOn,
                      r1.UserId
                   });

谁能纠正我。我想在这里使用左外连接或任何其他替代方法。

【问题讨论】:

    标签: c# linq entity-framework-5


    【解决方案1】:

    如果我美化你的 SP 的代码,我会得到:

    DECLARE @UserId int 
    SET @UserId = 12435 
    
    SELECT 
         P.PID
        ,P.PropertyName
        ,P.SBUArea
        ,P.ListedOn 
        ,P.Availability
        ,P.Price
        ,F.UserID
        ,F.PID AS FavProjId  
    FROM Property AS P 
    LEFT JOIN Favorite AS F
        ON (F.PID=P.PID AND F.UserID = @UserId)
    

    现在我想知道您是否需要 SQL 的 WHERE 子句中的 UserId,或者真的在联接中。

    但无论如何,这里是该 SQL 的 LINQ 等效项:

    System.Int64 __UserId = 12435;
    
    var query = (
        from P in Repo.Property
        from F in Repo.Favorite
             .Where(fav=> fav.PID == P.PID && fav.UserID == __UserId)
             .DefaultIfEmpty() // <== makes join left join
        select new
        {
             PID = P.PID
            ,PropertyName = P.PropertyName
            ,SBUArea = P.SBUArea
            ,ListenOn = P.ListedOn 
            ,Availabiity = P.Availability
            ,Price = P.Price
            ,UserId = F.UserID
            ,FavProjId = F.PID 
        }
    
    );
    
    var data = (query).ToList();
    

    【讨论】:

    • 你能告诉我为什么不加入关键字。如果没有,请告诉我原因。谢谢
    • @User:因为连接被转换为内部连接。你说你想要的 SQL 中有一个左连接。基本问题是,在 LINQ 中,您无法在 join 关键字上指定 left/right/inner。所以它总是进行内部连接。但是您仍然可以像在 SQL-92 中那样进行连接,其中也没有左/右/内连接关键字。 java2s.com/Code/Oracle/Table-Joins/…
    • 从那里的例子:SELECT e.ename, j.jobtitle FROM employee e, job j WHERE e.empno = j.empno (+); (+) 相当于 DefaultIfEmpty。
    • 你的意思是 DefaultIfEmpty() 在上述情况下本身就是一个连接(外连接)。
    • @User:我的意思是“DefaultIfEmpty”相当于 JOIN 关键字之前的“LEFT”修饰符。如果未指定任何内容,则单独的 JOIN 只是“INNER JOIN”的缩写。左连接始终是外连接。 “左内连接”(在 SQL 中出现语法错误)与内连接相同。外部是可选的,并且允许它的唯一原因是 SQL-92-syntax 向后兼容。语法: ::= [ { INNER | { { 左 |右 |完整 } [ 外部 ] } } [ ] ] 加入
    【解决方案2】:

    在您的选择中使用匿名对象

    var result = from t in table1
                 join x in table2
                 on t.id equals x.id
                 select new { id = t.id, col1 = t.col1, col2 = x.col2 }
    

    【讨论】:

    • 问题说明了任何替代方案,当然结果比用于获取它的连接更重要。
    【解决方案3】:

    如果你将 where 子句放在 join 之后,你可能会得到空引用异常,因为 DefaultIfEmpty 为不匹配的行返回默认值。您可以在加入之前过滤记录,如下所示:-

    var result=(from p in Properties
                join f in Favorites.Where(x => x.UserID == userId)
                on p.PID equals f.PID into r
                from r1 in r.DefaultIfEmpty()
                select new
                {
                    p.PID,
                    p.PropertyName,                       
                    p.SBUArea, 
                    p.ListedOn,
                    r1.UserId
                });
    

    请注意,您需要使用r1 访问Favorites 的属性。

    更新:

    据我了解,您需要 Property 表中的所有记录,并且只需要 Favorite 表中的匹配行。但是您的收藏表上有一个过滤器,因此最终的数据源会有所不同。让我通过这个例子来说明我的观点:-

    假设您在Property 表中有以下数据:-

    PID    PropertyName    Availability    Price
     1          aaa            true         20
     2          bbb            false        10
     3          ccc            true         50
     4          ddd            false        80
     5          eee            true         55
     6          fff            false        70
    

    Favorite这样的表:-

    FID    PID    UserId
     1      4      1001
     2      2      1005
     3      5      1007
    

    假设您想要 UserId 1005 的所有记录,那么结果应该包含从 1 到 6 的所有属性 ID,即使 UserId 1005 与属性 ID 的 4 和 2 不匹配,对吗?所以上面的查询就是按照这个理解。使用相同的示例和输出检查此Fiddle

    【讨论】:

    • @User - 这一定是因为userId过滤器而发生的,否则它将从两个表中返回记录。
    • 因为我的问题中有一个 sql 查询,它工作正常。我的意图是传递 userId 并从 Property 表中获取所有记录,并根据 userId 从收藏夹中匹配记录。
    • @User - 您确定您在匿名类型中获取r1.UserIDr1.PID
    • 这样做也没有给出所需的结果。
    • @User - 检查我的更新,并根据我的示例让我知道您期望的输出。为简单起见,我使用对象完成了此操作。
    猜你喜欢
    • 1970-01-01
    • 2021-02-20
    • 2018-12-04
    • 2011-03-19
    • 1970-01-01
    • 2012-10-21
    • 2019-05-03
    • 1970-01-01
    • 2014-02-24
    相关资源
    最近更新 更多