linq:在不同类型的条件下左加入 linq
Posted
技术标签:
【中文标题】linq:在不同类型的条件下左加入 linq【英文标题】:linq: left join in linq with different type of conditions 【发布时间】: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();
我无法在此处包含左连接
【问题讨论】:
【参考方案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();
因为实体框架知道有一个外键的一对多,它会为你做正确的左外连接。
【讨论】:
以上是关于linq:在不同类型的条件下左加入 linq的主要内容,如果未能解决你的问题,请参考以下文章