A sequência contém mais de um elemento

110

Estou tendo alguns problemas para obter uma lista do tipo "RhsTruck" por meio do Linq e fazer com que sejam exibidos.

RhsTruck só tem as propriedades Marca, Modelo, Serial etc ... RhsCustomer tem as propriedades CustomerName, CustomerAddress, etc ...

Continuo recebendo o erro "A sequência contém mais de um elemento". Alguma ideia? Estou abordando isso da maneira errada?

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
fonte
1
Use take <> , o mesmo que a função de agregação SQL Top () ,.Take(1).SingleOrDefault();
Thein

Respostas:

254

O problema é que você está usando SingleOrDefault. Este método só terá sucesso quando as coleções contiverem exatamente 0 ou 1 elemento. Eu acredito que você está procurando FirstOrDefaultaquele que terá sucesso, não importa quantos elementos estejam na coleção.

JaredPar
fonte
8
Calvin, nesse caso você deve aceitar esta resposta como uma solução
Dejan Milicic
24
-1 "O problema é que você está usando SingleOrDefault" - pelo que pude perceber, o OP está procurando por um ID de cliente que (presumo) deve ser exclusivo, portanto, SingleOrDefaulté na verdade mais apropriado do que FirstOrDefault. Além disso, isso realmente levantou um problema mais sério com o design do banco de dados do OP, pois mostra que é possível adicionar 2 clientes com o mesmo ID!
James
27
@James, o OP afirmou que minha resposta estava correta e a exceção afirma claramente que a coleção tem mais de um elemento que impede SingleOrDefaultde funcionar. É verdade que pode ser possível ter um design de banco de dados melhor aqui, mas isso parece mais apropriado como um comentário sobre o OP e não como -1 em uma resposta.
JaredPar
9
IMO, o problema subjacente é basicamente o design do banco de dados, pois mostra que 2 IDs de cliente exclusivos podem ser adicionados ao banco de dados. SingleOrDefaultestá lançando uma exceção porque há uma inconsistência entre o que o método espera e o que está encontrando. Portanto, embora sua resposta interrompa a exceção, para mim, ela não resolve o problema, é mais um cartão de "saia da prisão", portanto -1.
James
2
Isso é enganoso! O uso de SingleOrDefaultentão cai quando você espera que uma coleção tenha 0 ou 1 itens e deseja verificar se isso acontece todas as vezes ...
Aquiles
23

SingleOrDefaultmétodo lança um Exceptionse houver mais de um elemento na sequência.

Aparentemente, sua consulta em GetCustomerestá encontrando mais de uma correspondência. Portanto, você precisará refinar sua consulta ou, provavelmente, verificar seus dados para ver por que está obtendo vários resultados para um determinado número de cliente.

Mehmet Aras
fonte
5
Use FirstOrDefault insted of SingleOrDefault..

SingleOrDefault retorna um elemento SINGLE ou nulo se nenhum elemento for encontrado. Se 2 elementos forem encontrados em seu Enumerable, ele lança a exceção que você está vendo

FirstOrDefault retorna o FIRST elemento encontrado ou nulo se nenhum elemento for encontrado. então se houver 2 elementos que correspondem ao seu predicado, o segundo é ignorado

   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
fonte
1

Para sua informação, você também pode obter este erro se o EF Migrations tentar ser executado sem nenhum Db configurado, por exemplo, em um projeto de teste.

Persegui isso por horas antes de descobrir que estava errando em uma consulta, mas, não por causa da consulta, mas porque foi quando o Migrations começou a tentar criar o Db.

Chris Moschini
fonte
0

Como @Mehmet está apontando, se o seu resultado retornar mais de 1 elemento, você precisa examinar seus dados, pois suspeito que não é por design que você tenha clientes compartilhando um número personalizado.

Mas, até o ponto, eu queria dar uma visão geral 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 mais expressões Linq, dê uma olhada em System.Linq.Expressions

Martin Sax
fonte