2017-01-16 7 views
1

EF6でMySQLを使用すると、DefaultIfEmptyがbug #80127に関連してMySQLでうまくサポートされないため、空の子コレクションの値を合計すると例外がスローされます。 DefaultIfEmptyで推奨されるアプローチを使用して子コレクションの合計

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; } 
} 

が無効clausule 'Project1の' が例外をスローします。 'ID'。これはMySQLの古いバグです。

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

それが正常に動作しますが、内側のクエリとSELECT文の繰り返しの多い非常に醜い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の代わりに、キャスト演算子を使用して、null以外の型をnull可能にすることができます。これは、MySQLコネクタで(均等に)動作します。

解決策は、受信者クラスのプロパティの種類によって異なります。

あなたがNULL可能結果を受け取ることができれば最高のクエリがシンプルであり、その場合には、次のとおりです。

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

それが非NULL可能タイプにする必要がある場合は、null合体演算子

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 }; 

最新のEF6.1.3でMySQL Connector/Netでテスト済み6.9.8

関連する問題