La secuencia contiene más de un elemento

110

Tengo algunos problemas para obtener una lista del tipo "RhsTruck" a través de Linq y hacer que se muestren.

RhsTruck solo tiene las propiedades Marca, Modelo, Serie, etc. RhsCustomer tiene propiedades CustomerName, CustomerAddress, etc.

Sigo recibiendo el error "La secuencia contiene más de un elemento". ¿Algunas ideas? ¿Me estoy acercando a esto de la manera incorrecta?

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();   
}
Owen Blacker
fuente
1
Use take <> , lo mismo con la función agregada SQL Top () ,.Take(1).SingleOrDefault();
Thein

Respuestas:

254

El problema es que estás usando SingleOrDefault. Este método solo tendrá éxito cuando las colecciones contengan exactamente 0 o 1 elemento. Creo que está buscando FirstOrDefaultcuál tendrá éxito sin importar cuántos elementos haya en la colección.

JaredPar
fuente
8
Calvin, en ese caso debería aceptar esta respuesta como una solución
Dejan Milicic
24
-1 "El problema es que está usando SingleOrDefault" - por lo que puedo deducir, el OP está buscando una identificación de cliente que (supongo) debería ser única, por lo tanto, en SingleOrDefaultrealidad es más apropiada que FirstOrDefault. Además, esto ha planteado un problema más serio con el diseño de la base de datos del OP, ya que muestra que es posible agregar 2 clientes con la misma ID.
James
27
@James, el OP declaró que mi respuesta era correcta y la excepción indica claramente que la colección tiene más de un elemento que impide SingleOrDefaultque funcione. Es cierto que puede ser posible tener un mejor diseño de base de datos aquí, pero parece más apropiado como un comentario sobre el OP y no como un -1 en una respuesta.
JaredPar
9
En mi opinión, el problema subyacente es en última instancia el diseño de la base de datos, ya que muestra que se pueden agregar 2 ID de cliente únicos a la base de datos. SingleOrDefaultestá lanzando una excepción porque hay una inconsistencia entre lo que espera el método y lo que encuentra. Entonces, aunque su respuesta detiene la excepción, para mí, en realidad no resuelve el problema, es más una tarjeta de "salir de la cárcel gratis", de ahí el -1.
James
2
¡Esto es engañoso! El uso de SingleOrDefaultentonces cae en cuando esperas que una colección tenga 0 o 1 elementos y quieres verificar que esto suceda cada vez ...
Achilles
23

SingleOrDefaultEl método arroja un Exceptionsi hay más de un elemento en la secuencia.

Aparentemente, su consulta en GetCustomerencuentra más de una coincidencia. Por lo tanto, deberá refinar su consulta o, lo más probable, verificar sus datos para ver por qué obtiene múltiples resultados para un número de cliente determinado.

Mehmet Aras
fuente
5
Use FirstOrDefault insted of SingleOrDefault..

SingleOrDefault devuelve un elemento ÚNICO o nulo si no se encuentra ningún elemento. Si se encuentran 2 elementos en su Enumerable, arroja la excepción que está viendo

FirstOrDefault devuelve el PRIMER elemento que encuentra o nulo si no se encuentra ningún elemento. entonces, si hay 2 elementos que coinciden con su predicado, el segundo se ignora

   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);
Muhammad Armaghan
fuente
1

Para su información, también puede obtener este error si EF Migrations intenta ejecutarse sin Db configurado, por ejemplo, en un proyecto de prueba.

Lo perseguí durante horas antes de darme cuenta de que se estaba cometiendo un error en una consulta, pero no por la consulta, sino porque fue cuando se activó Migraciones para intentar crear el archivo Db.

Chris Moschini
fuente
0

Como señala @Mehmet, si su resultado devuelve más de 1 elemento, entonces debe examinar sus datos, ya que sospecho que no es por diseño que tenga clientes que compartan un número de cliente.

Pero hasta el punto que quería darles una descripción general rápida.

//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();

para más expresiones Linq, eche un vistazo a System.Linq.Expressions

Martin Sax
fuente