2015-01-09 22 views
12

Bu satırları içeren büyük bir Entity Framework sorgum var. Verileri gerçekleşmek zamanToplam() Entity Framework Query'de null döndürüyor

var programs = from p in Repository.Query<Program>() 
       where p.OfficeId == CurrentOffice.Id 
       let totalCharges = p.ProgramBillings.Where(b => b.Amount > 0 && b.DeletedDate == null).Select(b => b.Amount).Sum() 
       let totalCredits = p.ProgramBillings.Where(b => b.Amount < 0 && b.DeletedDate == null).Select(b => -b.Amount).Sum() 
       let billingBalance = (totalCharges - totalCredits) 

, aşağıdaki hatayı alıyorum: Ben (iki tip atmalarını eklenen) aşağıdaki gibi benim sorguyu değiştirirseniz

The cast to value type 'Decimal' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.

, hata kaybolur.

var programs = from p in Repository.Query<Program>() 
       where p.OfficeId == CurrentOffice.Id 
       let totalCharges = (decimal?)p.ProgramBillings.Where(b => b.Amount > 0 && b.DeletedDate == null).Select(b => b.Amount).Sum() 
       let totalCredits = (decimal?)p.ProgramBillings.Where(b => b.Amount < 0 && b.DeletedDate == null).Select(b => -b.Amount).Sum() 
       let billingBalance = (totalCharges - totalCredits) 

Bunu anlamıyorum. ProgramBilling.Amount, null olmayan bir Ondalıktır. Interkisense, Sum() aramasının üzerine geldiğimde, Ondalık tipi döndürdüğünü söylüyor. Yine de ek testler, ikinci versiyonumda,ve totalCredits'un her ikisi de ProgramBillings'un veri içermediği satırlar için null olarak ayarlandığını doğruladı.

Sorular:

  1. Ben Sum() boş koleksiyonu için 0 döndürdü anladı. Hangi koşullar altında bu doğru değil mi?

  2. Ve bazen bu doğru değilse, neden Sum() üzerinde gezindiğimde, Intellisense ondalık ve Ondalık değil tipini döndürdüğünü gösterir? Görünüşe göre Intellisense sahip olduğum aynı anlayışa sahipti.

DÜZENLEME:

Bu kolay bir düzeltme Sum() ?? 0m böyle bir şey yapmak olduğunu görünüyor. Ama bu bana hata veren yasadışı:

Operator '??' cannot be applied to operands of type 'decimal' and 'decimal'

+3

Bu gönderiye baktınız: http://stackoverflow.com/questions/17593371/how-to-force-linq-sum-to-return-0-while-source-collection-is-empty –

+0

@JonathanWood: "Ama yine de bunun neden gerekli olduğu konusunda kafam karıştı" tekrar bağlantılı sorunun başlığını oku. Gerekli çünkü koleksiyon boş. Boş bir koleksiyonun toplamının null değilse ne olmasını isterdiniz? Açıkça '0', '0' bir toplam için mükemmel geçerli bir değer olduğundan kesmiyor. –

+0

@DavidTansey: Bunu gördüm, ama sorumun sonunda sorduğum soruların hiçbiri hakkında hiçbir ipucu vermiyor. Gerektiği gibi alacağım yaklaşım budur. Sadece nedenini anlamak istedim. –

cevap

8

I understood Sum() returned 0 for an empty collection. Under what circumstances is this not true?

Nesnelere LINQ kullanarak değilken, burada olduğu gibi. Burada bu sorguyu SQL'e çeviren bir sorgu sağlayıcınız var. SQL işlemi, SUM işleci için farklı anlamlara sahiptir.

And if sometimes that is not true, then why when I hover over Sum(), Intellisense shows it returns type Decimal and not Decimal? It appears Intellisense had the same understanding that I had.

C# LINQ SUM işleci null değer döndürmez; Null olmayan bir değere sahip olması gerekir, ancak SQL SUM işleci farklı semantiklere sahiptir, 0 değil boş bir kümeyi toplarken null döndürür. null değerinin, C# değerinin sıfır olmayan bir değer gerektirdiği bir bağlamda sağlanmış olması gerçeği, her şeyin kesilmesinin tüm nedeni. C# LINQ SUM işleci burada nullable bir değer döndürdüyse, null yalnızca sorunsuz bir şekilde iade edilebilir.

Bu hataya neden olduğunu göstermek için C# işleci ve SQL işleci arasındaki farktır. koleksiyon boşken

+0

Açıklama için teşekkürler. C# ve SQL semantiği arasındaki farkla ilgili olduğunu düşünmüştüm ama derleyicinin burada C# semantiği olduğunu varsayarak bir eksiklik gibi görünüyor. Eğer yapmadıysa, boş değer döndürme değerini sıfıra zorlamak için basitleştirici operatörü kullanabilirdim. –

+0

@JonathanWood LINQ, her yerde, her zaman sorgulanabilecek her şeyin anlamlarını destekleyemez. Eğer denerse, onu neredeyse kullanılamaz hale getirmek için o kadar çok şey olurdu. Hangi tür işlemlerin destekleneceği, nelerin desteklenmemesi ve hangi anlamların desteklenmesi gerektiği konusunda belirli kararlar alması gerekiyordu. Daha sonra, sorgulama sorusu ne olursa olsun LINQ'da açıklanabilecek işlemleri eşleştirmek için sorgu sağlayıcısının sorumluluğundadır. Bu durumun gerçekliği, her şeyin 1: 1 ile eşleşmeyeceği. – Servy

+0

Bunu anlıyorum, ama sonra bu durumda, daha az katı olarak yazılan yapılara benziyor. Her neyse, bunun bir açıklamasını bulmakta zorlandım. Ve soru biraz dikkat çekti. Tekrar teşekkürler. –

0

benim EF sorguları birinde aynı sorunu var, bunun için bir hızlı düzeltme null ondalık yayın yapmak için ise:

var total = db.PaiementSet.Sum(o => (Decimal?)o.amount) ?? 0M; 

yardımcı olur umarım.

+0

Benim için çalışmadı. – Sentinel

0

.Sum'dan önce bir DefaultIfEmpty ekleyin (0.0M)