2017-01-16 130 views
1

當我彙總來自空子集合的值時,使用MySQL和EF6會引發異常,因爲DefaultIfEmpty與bug #80127中的相關信息不兼容。子集合中的總和

public class Foo 
{ 
    public int Id { get; set; } 
    public decimal Total { get; set; } 
    public virtual IList<Bar> Bars { get; set; } 
} 

public class Bar 
{ 
    public int Id { get; set; } 
    public int FooId { get; set; } 
    public virtual Foo Foo { get; set; } 
    public decimal Received { get; set; } 
} 

對DefaultIfEmpty使用推薦的方法會拋出一個異常,其中包含無效的where clausule'Project1'。'Id'。這是MySQL的一箇舊bug。

var result = db.Foo.Select(f => new { 
    Total = f.Total, 
    Received = f.Bars.Select(b => b.Received).DefaultIfEmpty().Sum() 
}); 

我使用內聯如果工作正常,但生成一個非常醜陋的SQL與許多內部查詢和重複的選擇語句。

var result = db.Foo.Select(f => new { 
    Total = f.Total, 
    Received = f.Bars.Any() ? f.Bars.Sum(b => b.Received) : 0 
}); 

有沒有更好的方法來避免DefaultIfEmpty?

回答

2

DefaultIfEmpty我通常更喜歡的替代方法是使用cast操作符將非空類型提升爲可空,它可以在MySQL連接器中工作(偶數)。

然後解決方案取決於您的接收器類屬性類型。

最好的是,如果你能接受一個可空的結果,在這種情況下,查詢很簡單:

var result = db.Foo.Select(f => new { 
    Total = f.Total, 
    Received = f.Bars.Sum(b => (decimal?)b.Received) 
}); 

如果它需要一個非空類型,可以使用空合併運算符

var result = db.Foo.Select(f => new { 
    Total = f.Total, 
    Received = f.Bars.Sum(b => (decimal?)b.Received) ?? 0 
}); 

但生成的SQL查詢是醜陋和低效的。

,你可以在這樣的情況下做的最好是使用(一個很煩人的)雙選招:

var result = db.Foo.Select(f => new { 
    f.Total, 
    Received = f.Bars.Sum(b => (decimal?)b.Received) 
}) 
.Select(r => new { 
    r.Total, 
    Received = r.Received ?? 0  
}; 

或(相當好)與let子句查詢語法:

var result = 
    from f in db.Foos 
    let received = f.Bars.Sum(b => (decimal?)b.Received) 
    select new { f.Total, Received = received ?? 0 }; 

使用MySQL Connector/Net測試最新的EF6.1.3 6.9.8