【问题标题】:linq: left join in linq with different type of conditionslinq:在不同类型的条件下左加入 linq
【发布时间】:2018-04-30 20:10:22
【问题描述】:

我有两张表,例如 PromotionalOffers 和 PromotionalOffersUsed
我正在使用连接获取匹配记录,现在我想包含不同的条件,例如 PromotionalOffers.ISVCSPId =10 和 PromotionalOffersUsed.OfferId 为 null

我已经使用 left join 在 sql 中编写查询,但我无法在 linq 中编写相同的查询

这里是我的 sql 查询

SELECT * 
FROM PromotionalOffers
left JOIN PromotionalOffersUsed ON PromotionalOffers.Id = PromotionalOffersUsed.OfferId where PromotionalOffers.ISVCSPId =10 and PromotionalOffersUsed.OfferId is null

我的 linq 查询是

(from s in db.PromotionalOffers
 join e in db.PromotionalOffersUsed on s.Id equals e.OfferId
 where s.ISVCSPId == iSVCSPData.Id
 select s).ToListAsync();

我无法在此处包含左连接

【问题讨论】:

    标签: c# mysql sql-server entity-framework


    【解决方案1】:

    对于左连接,你必须这样做,以下是 linq 中左外连接的示例

    var leftFinal =
            from l in lefts
            join r in rights on l equals r.Left into lrs
            from lr in lrs.DefaultIfEmpty()
            select new { LeftId = l.Id, RightId = ((l.Key==r.Key) ? r.Id : 0 };
    

    查询

    SELECT * 
    FROM PromotionalOffers
    left JOIN PromotionalOffersUsed ON PromotionalOffers.Id = PromotionalOffersUsed.OfferId where PromotionalOffers.ISVCSPId =10 and PromotionalOffersUsed.OfferId is null
    

    linq 中的试探性查询

    var leftFinal =
            (from l in PromotionalOffers.Where(p=> p.ISVCSPId ==10) 
            join r in PromotionalOffersUsed on l.ID equals r.OfferId  into lrs
            from lr in lrs.DefaultIfEmpty()
            select 
              new { LeftId = l.Id, RightId = ((l.ID==r.OfferId  ) ? r.OfferId   : -1 }
            ).where(d=> d.RightID != -1);
    

    【讨论】:

    • 感谢您的快速回复,但在选择我需要检查条件的字段之前。
    【解决方案2】:

    这样试试;

    (from s in db.PromotionalOffers
     join e in db.PromotionalOffersUsed on s.Id equals e.OfferId into joinT
     from e in joinT.DefaultIfEmpty()
     where s.ISVCSPId == 10 && (e == null || e.OfferId == null)
     select new { PromotionalOffers = s, PromotionalOffersUsed = joinT } ).ToListAsync();
    

    【讨论】:

    • 感谢您的快速回复,但我无法让 e 处于检查状态
    【解决方案3】:

    显然,PromotionalOffers 之间存在一对多关系 和PromotionalOffersUsed:每个PromotionalOffer 有零个或多个PromotionalOffersUsed,每个PromotionalOffersUsed 恰好属于一个PromotionalOffer

    如果您遵循entity framework conventions to design this one-to-many 关系,则不需要进行连接,也不需要左外连接,而是使用 ICollection 类:

    class PromotionalOffer
    {
        public int Id {set; set;}
        // a PromotionalOffer has zero or more PromotionalOfferUsed
        public virtual ICollection<PromotionalOfferUsed> PromitionalOffersUsed {get; set;}
        ...
    }
    class PromotionalOfferUsed
    {
        public int Id {set; set;}
        // every PromotionalOffersUsed belongs to exactly one PromotionalOffer
        // using foreign key:
        public int PromotionalOfferId {get; set;}
        public PromotionalOffer PromotionalOffer {get; set;}
        ...
    }
    class MyDbContext: DbContext
    {
        public DbSet<PromotionalOffer> PromotionalOffers {get; set;}
        public DbSet<PromotionalOfferUsed> PromotionalOffersUsed {get; set;
    }
    

    通常,这足以让实体框架知道您设计了一对多关系。

    我们需要一些流畅的 API 的唯一原因是奇怪的复数:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // PromotionalOffersUsed are stored in a table with name PromotionOffersUsed:
        modelBuilder.Entity<PromotionalOfferUsed>().ToTable("PromotionalOffersUdsed");
    
        // Every PromotionalOffer has zero or more PromotionalOfferUsed
        // every PromotionalOfferUsed belongs to exactly one (required) PromotionalOffer
        // using foreign key PromtionalOfferId
        modelBuilder.Entity<PromotionalOffer>
            .HasMany(promotionalOffer => promotionalOffer.PromotionalOffersUsed)
            .WithRequired(promotionalOfferUsed => promotionOfferUsed.PromotionalOffer)
             .HasForeignKey(post => post.BlogId);
    
        base.OnModelCreating(modelBuilder);
    }
    

    再一次,如果您有标准的单数和复数(Person/Persons;Account/Accounts,Order/Orders),则不需要这个流畅的 API。

    现在您的查询:考虑集合,而不是联接。

    给我所有 ISVCSPId 等于 10 的 PromotionalOffers 他们所有的 PromotionalOffersUsed 的 OfferId 等于 null

    using (var dbContext = new MyDbContext())
    {
        var result = dbContext.PromotionalOffers
            .Where(promotionalOffer => promotionalOffer.ISVCSPID == 10)
            .Select(promotionalOffer => new
            {   // select only the properties you will be using:
                ISVCSPID = promotionalOffers.ISVSPID,
                ... // other properties from promotionalOffers
    
                PromotionalOffersUsed = promotionalOffers.PromtionalOffersUsed
                    .Where(promotionalOffersUsed => promotionalOffersUsed.OfferId == null)
                    .Select(promotionalOffersUsed => new
                    {
                         // again: select only the properties of PromotionalOffersUsed
                         // that you will be using
                         Id = promotionalOffersUsed.Id,
                         ... // other properties
                    })
                    .ToList();
            }
    }
    

    因为实体框架知道有一个外键的一对多,它会为你做正确的左外连接。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多