简体   繁体   中英

Left join in Entity Framework with 1-to-many relation

I have five tables:

Coupons
Coupon_Redemptions
User_Coupon
Wash
Account

This is SQL Query that works in SQL Server and Entity Raw SQL , but can't get it to work with LINQ because 1-to-many releations, with lazy loading can't manage to get it because User_coupons, Wash... are collections.

SELECT 
    C.Id AS "CouponId", C.Coupon_code AS "CouponCode", 
    C.Discount_amount AS "DiscountAmount", 
    C.Valid_for_all AS "ValidForAll", C.Expiration_date AS "ExpirationDate", 
    R.Redemption_date AS "RedemptionDate",
    U.Date_added AS "DateAddedToUser", W.Id AS "WashId", A.Name  
FROM 
    Coupon C
    LEFT JOIN User_coupon U on U.CouponId = C.Id
    LEFT JOIN Coupon_redemption R on R.CouponId = C.Id
    LEFT JOIN Wash W on W.CouponId = C.Id
    LEFT JOIN Account A on U.AccountId = A.Id

Here is snippet of Relation diagram在此处输入图片说明

Tried variation on this query, it returns one row. But it looks perfect.

var results =
                from c in db.Coupons
                from u in c.User_coupon.DefaultIfEmpty()
                from r in c.Coupon_redemption.DefaultIfEmpty()
                from w in c.Washes.DefaultIfEmpty()
                select new {
                    CouponId = c.Id,
                    CouponCode = c.Coupon_code,
                    DiscountAmount = c.Discount_amount,
                    ValidForAll = c.Valid_for_all,
                    ExpirationDate = c.Expiration_date,
                    RedemptionDate = r.Redemption_date,
                    DateAddedToUser = u.Date_added,
                    WashId = w.Id
                };

Result to String:

SELECT[Extent1].[Id] AS [Id], [Extent1].[Coupon_code] AS [Coupon_code], [Extent1].[Discount_amount] AS [Discount_amount], [Extent1].[Valid_for_all] AS [Valid_for_all], [Extent1].[Expiration_date] AS [Expiration_date], [Extent3].[Redemption_date] AS [Redemption_date], [Extent2].[Date_added] AS [Date_added], [Extent4].[Id] AS [Id1] 
FROM [dbo].[Coupon] AS [Extent1] 
LEFT OUTER JOIN [dbo].[User_coupon] AS [Extent2] ON [Extent1].[Id] = [Extent2].[CouponId]
LEFT OUTER JOIN [dbo].[Coupon_redemption] AS [Extent3] ON [Extent1].[Id] = [Extent3].[CouponId]
LEFT OUTER JOIN [dbo].[Wash] AS [Extent4] ON [Extent1].[Id] = [Extent4].[CouponId]

Well, they are collections (with or without lazy loading) when the object containing them is materialized (ie you work through object instance). When used inside LINQ to Entities queries, they are simple table navigations (joins).

The rules are simple. To get the equivalent of SQL inner join for collection navigation property, you use

from child in parent.Collection

and respectively for left outer join:

from child in parent.Collection.DefaultIfEmpty()

For reference navigation property you can't specify explicitly the type of the join - it depends on (is controlled by) whether the relationship is required or optional. And instead of from , you can use let or directly the navigation property to get the SQL query join equivalent.

With that being said, the equivalent LINQ query would be something like this:

var query = 
    from c in dbContext.Coupons
    from u in c.User_coupon.DefaultIfEmpty()
    from r in c.Coupon_redemptions.DefaultIfEmpty()
    from w in c.Washes.DefaultIfEmpty()
    let a = u.Account
    select new
    {
        CouponId = c.Id,
        CouponCode = c.Coupon_code,
        DiscountAmount = c.Discount_amount,
        ValidForAll = c.Valid_for_all,
        ExpirationDate = c.Expiration_date, 
        RedemptionDate = r.Redemption_date,
        DateAddedToUser = u.Date_added,
        WashId = w.Id,
        Name = a.Name,          
    };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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