'Int32' değer türüne yayınlama, gerçekleşen değer boş olduğu için başarısız oldu


193

Takip koduna sahibim. Hata alıyorum:

"'Int32' değerine aktarma işlemi, gerçekleşen değer boş olduğu için başarısız oldu. Sonuç türünün genel parametresi veya sorgu nullable türü kullanmalıdır."

CreditHistory tablosunda kayıt olmadığında.

var creditsSum = (from u in context.User
                  join ch in context.CreditHistory on u.ID equals ch.UserID                                        
                  where u.ID == userID
                  select ch.Amount).Sum();

Boş değerleri kabul etmek için sorguyu nasıl değiştirebilirim?

Yanıtlar:


330

Linq-sql sorgusu kod olarak yürütülmez, daha çok SQL'e çevrilir. Bazen bu beklenmedik davranışlar yaratan bir "sızdıran soyutlama" dır.

Böyle bir durum, farklı yerlerde beklenmedik boş değerlerin olabileceği boş işlemdir. ...DefaultIfEmpty(0).Sum(0)hiçbir eleman ve sql SUMgetirisi olmayabilir bu (oldukça basit) durumda yardımcı nullolurken c # 0 bekliyoruz.

Daha genel bir yaklaşım, oluşturulan SQL'in beklenmedik bir boş döndürme riski olduğunda ??çevrilecek olan kullanımıdır COALESCE:

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select (int?)ch.Amount).Sum() ?? 0;

Bu ilk yayınları için int?bu ifadesi gerçekte dönebilmek C # derleyicisi anlatmak için nullbile olsa Sum()döner bir int. Daha sonra davanın ??üstesinden gelmek için normal operatörü kullanırız null.

Bu cevaba dayanarak, hem LINQ to SQL hem de LINQ to Entities için ayrıntıları içeren bir blog yazısı yazdım .


3
teşekkürler Anders, DefaultIfEmpty (0) .Sum () ile çözüm benim için iyi çalışıyor. Ayrıca (int?) İle ikinci çözümü denedim ... ?? 0 ..., ama eskisi gibi aynı istisnayı atar ..
zosim

Sonunda bunu test etmek için ayarladım ve ayarladım, bu yüzden şimdi ikinci versiyon da çalışıyor.
Anders Abel

1
Sum () ve diğer toplama işlevleri boş bir veri kümesine uygulandığında null değerini döndürür. Tanımlarının aksine, gerçekte altta yatan türün null olabilecek bir sürümünü döndürürler.
Suncat2000

2
@recursive: Örneğiniz, LINQ-to-SQL (veya LINQ-to-Entities) değil, LINQ-to-Objects'dir. Temelindeki veri sağlayıcıları farklı davranmalarını sağlar.
Suncat2000

Bu iyi bir fikirdi. Nulllable özelliklere sahip dönüş nesnesimi güncelledim ve bu bir cazibe olarak çalıştı.
Kremena Lalova

8

AmountBoş bir alana izin vermek için, boş değerleri 0'a dönüştürmek için boş değer birleştirme işlecini kullanın.

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch.Amount ?? 0).Sum();

1
ipucunu kullandığımda derleyici diyor ki: Operatör '??' 'int' ve 'int' türündeki işlenenlere uygulanamaz. bir şey mi unuttum?
zosim

@zosim: Oyuncuyu önce eklemenin nedeni bu int?.
Anders Abel

int ekledim, ama aynı istisna. Dev env olduğunda size minnettar olacağım. bu sözdiziminde neyin yanlış olduğunu kontrol etmek için.
zosim

1
@zosim: Sorunu anlamıyorum. Bir Amountise int, o zaman zaten boş olamayacağından eminiz ve birleşme gereksizdir. Söylediğiniz hatayı Amountalıyorsanız, null değerine sahip değilsiniz, bu sadece bir int, bu durumda belki de null'lara izin vermek için tasarımcıdaki linq2sql dbml sütununuzu değiştirmeniz gerekir.
özyinelemeli

1
@recursive: Tutar int, sorun değil. Tutar zaten bir değere sahip. CreditHistory tablosu boş olduğu için yukarıdaki hatanın oluştuğunu düşünüyorum. Kullanıcı tablosunda bir kayıt var ve CreditHistory tabloda 0 kayıtları var ve hata oluştu. DefaultIfEmpty (0) .Sum () kullandığımda iyi çalışıyor, ama ?? 0 hata veriyor. Başka bir sorum bu durumda en iyi uygulama nedir? DefaultIfEmpty (0)? thanks
zosim

4

aggregateEylem gerçekleştirmek için öğeleri almayan bir işlev kullanıyorsunuz , linq sorgusunun aşağıdaki gibi bir sonuç verdiğini doğrulamanız gerekir:

var maxOrderLevel =sdv.Any()? sdv.Max(s => s.nOrderLevel):0

11
Bu, sdv'nin iki kez çalıştırılmasını sağlar. IQueryables
Ody

4

Bir görünümden seçim yapmaya çalışırken bu hata mesajı vardı.

Sorun, görünümün yakın zamanda bazı yeni boş satırlar (SubscriberId sütununda) kazanmış olması ve EDMX'te (önce EF veritabanı) güncellenmemiş olmasıydı.

Sütunun çalışması için Nullable tipi olması gerekiyordu.

var dealer = Context.Dealers.Where (x => x.dealerCode == dealerCode) .FirstOrDefault ();

Görünümü yenilemeden önce:

public int SubscriberId { get; set; }

Görünüm yenilendikten sonra:

public Nullable<int> SubscriberId { get; set; }

EDMX'te görünüm silme ve geri ekleme işlemi işe yaradı.

Umarım birine yardımcı olur.


Bu da benim sorunum ve
Simon Nicholls

4

Bu kodu kullandım ve doğru yanıt verir, sadece çıkış değeri null edilebilir.

var packesCount = await botContext.Sales.Where(s => s.CustomerId == cust.CustomerId && s.Validated)
                                .SumAsync(s => (int?)s.PackesCount);
                            if(packesCount != null)
                            {
                                // your code
                            }
                            else
                            {
                                // your code
                            }

1

Bu sorunun zaten cevaplandığını görüyorum. Ancak bunun iki ifadeye bölünmesini istiyorsanız, aşağıdakiler düşünülebilir.

var credits = from u in context.User
              join ch in context.CreditHistory 
                  on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch;

var creditSum= credits.Sum(x => (int?)x.Amount) ?? 0;

0

Entity Framework 6'da şu kodla çalışma zamanında bu hatayı aldım:

var fileEventsSum = db.ImportInformations.Sum(x => x.FileEvents)

LeandroSoares'ten güncelleme:

Bunu tek bir yürütme için kullanın:

var fileEventsSum = db.ImportInformations.Sum(x => (int?)x.FileEvents) ?? 0

Orijinal:

Bunu değiştirdi ve sonra çalıştı:

var fileEventsSum = db.ImportInformations.Any() ? db.ImportInformations.Sum(x => x.FileEvents) : 0;

1
Bu iki kez çalıştırmaz mı?
nawfal

Bu iyi bir cevap değil. DB'den iki kez alınacaktır.
Leandro Soares

@nawfal Bu doğrudur, ancak bir çalışma zamanı hatasından çok daha iyidir. Linq-sql'yi kesinlikle kullanabilirsiniz, ancak lambda ile daha zordur. Elbette istisnayı yakalayabilirsiniz, ancak çözümün iki yürütmeden daha kötü olduğunu düşünüyorum.
Ogglas

@LeandroSoares yukarıdaki yoruma bakınız
Ogglas

1
@LeandroSoares İyi biri! Cevabımı güncelledim ve sağladığınız kodu ve bunun yerine neden açıklamayı kullandım.
Ogglas

0

Ben de aynı sorunla karşı karşıya ve "?" Kullanarak nullable sütun yaparak çözüldü Şebeke.

Sequnce = db.mstquestionbanks.Where(x => x.IsDeleted == false && x.OrignalFormID == OriginalFormIDint).Select(x=><b>(int?)x.Sequence</b>).Max().ToString();

Bazen null döndürülür.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.