La sequenza contiene più di un elemento


110

Ho dei problemi con l'acquisizione di un elenco di tipo "RhsTruck" tramite Linq e il modo in cui vengono visualizzati.

RhsTruck ha solo proprietà Marca, Modello, Seriale ecc ... RhsCustomer ha proprietà CustomerName, CustomerAddress, ecc ...

Continuo a ricevere l'errore "La sequenza contiene più di un elemento". Qualche idea? Mi sto avvicinando a questo nel modo sbagliato?

public RhsCustomer GetCustomer(string customerNumber)
{
    using (RhsEbsDataContext context = new RhsEbsDataContext() )
    {
        RhsCustomer rc = (from x in context.custmasts
                          where x.kcustnum == customerNumber
                          select new RhsCustomer()
                        {
                            CustomerName = x.custname,
                            CustomerAddress = x.custadd + ", " + x.custcity
                            CustomerPhone = x.custphone,
                            CustomerFax = x.custfax
                        }).SingleOrDefault();
        return rc;
    }
}

public List<RhsTruck> GetEquipmentOwned(RhsCustomer cust)
{
    using (RhsEbsDataContext context = new RhsEbsDataContext())
    {
        var trucks = (from m in context.mkpops
                      join c in context.custmasts
                        on m.kcustnum equals c.kcustnum
                      where m.kcustnum == cust.CustomerNumber
                      select new RhsTruck
                    {
                        Make = m.kmfg,
                        Model = m.kmodel,
                        Serial = m.kserialnum,
                        EquipID = m.kserialno1,
                        IsRental = false
                    }).ToList();
        return trucks;
    }
}

protected void Page_Load(object sender, EventArgs e)
{
    string testCustNum = Page.Request.QueryString["custnum"].ToString();

    RhsCustomerRepository rcrep = new RhsCustomerRepository();
    RhsCustomer rc = rcrep.GetCustomer(testCustNum);
    List<RhsTruck> trucks = rcrep.GetEquipmentOwned(rc);

    // I want to display the List into a Gridview w/auto-generated columns
    GridViewTrucks.DataSource = trucks;
    GridViewTrucks.DataBind();   
}

1
Usa take <> , lo stesso con la funzione di aggregazione SQL Top () ,.Take(1).SingleOrDefault();
Thein

Risposte:


254

Il problema è che stai usando SingleOrDefault. Questo metodo avrà successo solo quando le raccolte contengono esattamente 0 o 1 elemento. Credo che tu stia cercando FirstOrDefaultquale avrà successo indipendentemente dal numero di elementi presenti nella raccolta.


8
Calvin, in quel caso dovresti accettare questa risposta come soluzione
Dejan Milicic

24
-1 "Il problema è che stai usando SingleOrDefault" - da quello che posso raccogliere l'OP sta cercando un ID cliente che (presumo) dovrebbe essere univoco, quindi, in SingleOrDefaultrealtà è più appropriato di FirstOrDefault. Inoltre, questo ha effettivamente sollevato un problema più serio con il design del database dell'OP in quanto mostra che è possibile aggiungere 2 clienti con lo stesso ID!
James,

27
@ James, l'OP ha affermato che la mia risposta era corretta e l'eccezione afferma chiaramente che la raccolta ha più di un elemento che impedisce SingleOrDefaultdi funzionare. È vero che potrebbe essere possibile avere un design del database migliore qui, ma sembra più appropriato come commento sull'OP e non un -1 su una risposta.
JaredPar

9
IMO il problema sottostante è in definitiva la progettazione del DB in quanto mostra che è possibile aggiungere 2 ID cliente univoci al database. SingleOrDefaultsta generando un'eccezione perché c'è un'incongruenza tra ciò che il metodo si aspetta e ciò che sta trovando. Quindi, anche se la tua risposta ferma l'eccezione, per me, in realtà non risolve il problema, è più una carta "esci di prigione" da cui il -1.
James

2
Questo è fuorviante! L'utilizzo per SingleOrDefaultpoi rientra quando ti aspetti che una collezione abbia 0 o 1 articoli e vuoi controllare che ciò accada ogni volta ...
Achilles

23

SingleOrDefaultmetodo genera un Exceptionse c'è più di un elemento nella sequenza.

Apparentemente, la tua query GetCustomersta trovando più di una corrispondenza. Quindi dovrai affinare la tua query o, molto probabilmente, controllare i tuoi dati per vedere perché stai ottenendo più risultati per un dato numero di cliente.


5
Use FirstOrDefault insted of SingleOrDefault..

SingleOrDefault restituisce un elemento SINGOLO o null se non viene trovato alcun elemento. Se vengono trovati 2 elementi nel tuo Enumerable, viene generata l'eccezione che stai vedendo

FirstOrDefault restituisce il PRIMO elemento che trova o null se non viene trovato alcun elemento. quindi se ci sono 2 elementi che corrispondono al tuo predicato, il secondo viene ignorato

   public int GetPackage(int id,int emp)
           {
             int getpackages=Convert.ToInt32(EmployerSubscriptionPackage.GetAllData().Where(x
   => x.SubscriptionPackageID ==`enter code here` id && x.EmployerID==emp ).FirstOrDefault().ID);
               return getpackages;
           }

 1. var EmployerId = Convert.ToInt32(Session["EmployerId"]);
               var getpackage = GetPackage(employerSubscription.ID, EmployerId);

1

Cordiali saluti, puoi anche ottenere questo errore se EF Migrations tenta di essere eseguito senza alcun database configurato, ad esempio in un progetto di test.

L'ho seguito per ore prima di capire che si trattava di un errore su una query, ma non a causa della query ma perché è stato quando Migrations ha iniziato a cercare di creare il database.


0

Come sta sottolineando @Mehmet, se il tuo risultato restituisce più di 1 elemento, devi esaminare i tuoi dati poiché sospetto che non sia previsto che i clienti condividano un numero personalizzato.

Ma al punto volevo darti una rapida panoramica.

//success on 0 or 1 in the list, returns dafault() of whats in the list if 0
list.SingleOrDefault();
//success on 1 and only 1 in the list
list.Single();

//success on 0-n, returns first element in the list or default() if 0 
list.FirstOrDefault();
//success 1-n, returns the first element in the list
list.First();

//success on 0-n, returns first element in the list or default() if 0 
list.LastOrDefault();
//success 1-n, returns the last element in the list
list.Last();

per ulteriori espressioni Linq dai un'occhiata a System.Linq.Expressions

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.