Domanda

Ho questo codice (ok, non lo so, ma qualcosa di simile: p)

    var dogs = Dogs.Select(ø => new Row
    {
            Name = ø.Name,
            WeightOfNiceCats = ø.Owner
              .Cats
              .Where(æ => !æ.Annoying)
              .Sum(æ => æ.Weight),
    });

Qui vado attraverso tutti i cani e riassumere il peso (in un decimale non annullabile) di tutti i gatti non-fastidiosi che ha lo stesso proprietario del cane. Naturalmente, più o meno tutti i gatti sono fastidiosi, così ottengo questo errore:

  

Il valore nullo non può essere assegnato ad un membro di tipo System.Decimal che è un tipo di valore non nullable.

Nessuno dei campi o chiavi esterne utilizzati possono essere nulli. Quindi l'errore si verifica quando la clausola Where non ha prodotto alcun gatti, che lo fa spesso. Ma come posso risolvere questo problema? Voglio per tornare 0 quando ciò accade. Provato con un DefaultIfEmpty() dopo la clausola Where, ma d'altra parte ottengo questo errore:

  

Il riferimento non impostato a un'istanza di un oggetto.

che credo sia comprensibile. Ho provato ad aggiungere un ?? dopo il Sum, ma poi non ci vorrà compilo a causa di questo errore:

  

Operatore '??' non può essere applicato a operandi di tipo 'decimale' e 'decimale'

Il che rende anche il senso di corso. Quindi cosa posso fare? Sarebbe bello se la cosa Sum appena tornato 0 quando non c'era niente per riassumere. O una dichiarazione SumOrZero di qualche tipo. Sarebbe difficile fare un metodo SumOrZero che ha lavorato con Linq2SQL?

È stato utile?

Soluzione

Questo è quello che ho finito con per ora:

.Sum(æ => (decimal?) æ.Weight) ?? 0.0M,

Questo funziona come un fascino.

Vorrei ancora preferiscono avere un SumOrZero ho potuto usare, che funzionerebbe esattamente come la Sum normale tranne che non sarebbe più tornato null per qualsiasi motivo. Come gli altri hanno fatto notare, questo sarebbe abbastanza facile da fare per IEnumerable, ma un po 'più icky di creare per IQueryable quindi sarebbe lavorare con Linq2SQL, ecc Quindi mi limiterò a lasciare le cose come che per ora. Anche se qualcuno si annoia un giorno e fare scrivere un SumOrZero per IQueryable che funziona con Linq2SQL per tutti i tipi numerici, per favore fatemelo sapere: D

Altri suggerimenti

In LINQ to Objects che sarebbe stato facile. Con LINQ to SQL sarà più difficile. Si potrebbe scrivere il proprio metodo di estensione che ha chiamato Queryable.Sum con un'espressione costruito da quello normale, con un cast al tipo nullable. Ho il sospetto che avresti bisogno di fare lo ?? 0m nel codice chiamante però. In altre parole, si potrebbe fare:

.SumOrNull(æ => æ.Weight) ?? 0M,

Se la firma per .SumOrNull potrebbe essere:

public static decimal? SumOrNull<TSource, decimal>(this IQueryable<TSource>,
    Func<TSource,decimal> projection)

Si potrebbe fondamentalmente scrivere che per tutti i tipi di valore supportati in Queryable. potrebbe scriverlo genericamente, e chiamare il metodo appropriato in Queryable utilizzando la riflessione, ma che sarebbe troppo icky.

Credo che si sta meglio fuori con quello che hai, ad essere onesti.

Il trucco hai già dato (.Sum(æ => (decimal?) æ.Weight) ?? 0.0M) è di circa il meglio che posso pensare per questo scenario quando si esegue come una query al database. Un po 'fastidioso, ma ci sono cose peggiori ...

A differenza di LINQ to Objects, non si può semplicemente aggiungere la tua metodo di estensione, in quanto deve essere mappato dal provider sottostante.

Si desidera utilizzare DefaultIfEmpty, che restituirà un IEnumberable con un unico elemento di 0, e che sarà semanticamente lo stesso come richiedete.

Come si dispone di un numero decimale annullabile, probabilmente si dovrà usare la seconda versione del metodo prendere 2 parametri.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top