当我对空子集合中的值求和时,将MySQL与EF6一起使用会抛出异常,因为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; }
}
使用DefaultIfEmpty的推荐方法会抛出一个带有无效的异常,其中包含了clausule&#39; Project1&#39;。&#39; Id&#39;。这是MySQL的一个老bug。
var result = db.Foo.Select(f => new {
Total = f.Total,
Received = f.Bars.Select(b => b.Received).DefaultIfEmpty().Sum()
});
我使用内联如果工作正常但会生成一个非常难看的SQL,其中包含大量内部查询和重复的select语句。
var result = db.Foo.Select(f => new {
Total = f.Total,
Received = f.Bars.Any() ? f.Bars.Sum(b => b.Received) : 0
});
有没有更好的方法来避免使用DefaultIfEmpty?
答案 0 :(得分:2)
我通常喜欢的DefaultIfEmpty
的替代方法是使用强制转换操作符将非可空类型提升为可空,这对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 6.9.8
测试最新的EF6.1.3