La séquence contient plus d'un élément

110

J'ai quelques problèmes pour saisir une liste de type "RhsTruck" via Linq et les faire afficher.

RhsTruck a juste les propriétés Make, Model, Serial etc ... RhsCustomer a les propriétés CustomerName, CustomerAddress, etc ...

J'obtiens toujours l'erreur "La séquence contient plus d'un élément". Des idées? Est-ce que j'aborde cela de la mauvaise façon?

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
la source
1
Utilisez take <> , idem avec la fonction d'agrégation SQL Top () ,.Take(1).SingleOrDefault();
Thein

Réponses:

254

Le problème est que vous utilisez SingleOrDefault. Cette méthode ne réussira que lorsque les collections contiennent exactement 0 ou 1 élément. Je crois que vous cherchez FirstOrDefaultce qui réussira quel que soit le nombre d'éléments de la collection.

JaredPar
la source
8
Calvin, dans ce cas, vous devriez accepter cette réponse comme une solution
Dejan Milicic
24
-1 "Le problème est que vous utilisez SingleOrDefault" - d'après ce que je peux comprendre, l'OP recherche un identifiant client qui (je suppose) devrait être unique, donc SingleOrDefaultplus approprié que FirstOrDefault. En outre, cela a en fait soulevé un problème plus grave avec la conception de la base de données de l'OP car cela montre qu'il est possible d'ajouter 2 clients avec le même ID!
James
27
@James, l'OP a déclaré que ma réponse était correcte et l'exception indique clairement que la collection contient plus d'un élément qui empêche SingleOrDefaultde fonctionner. Certes, il peut être possible d'avoir une meilleure conception de base de données ici, mais cela semble plus approprié en tant que commentaire sur l'OP et non un -1 sur une réponse.
JaredPar
9
OMI, le problème sous-jacent est en fin de compte la conception de la base de données, car elle montre que 2 ID client uniques peuvent être ajoutés à la base de données. SingleOrDefaultlance une exception car il y a une incohérence entre ce que la méthode attend et ce qu'elle trouve. Donc, bien que votre réponse arrête l'exception, pour moi, elle ne résout pas réellement le problème, c'est plutôt une carte «sortir de prison sans frais» d'où le -1.
James
2
C'est trompeur! L'utilisation de SingleOrDefaultalors tombe lorsque vous vous attendez à ce qu'une collection contienne 0 ou 1 élément et que vous voulez vérifier que cela se produit à chaque fois ...
Achilles
23

SingleOrDefaultrenvoie un Exceptions'il y a plus d'un élément dans la séquence.

Apparemment, votre requête en GetCustomerrecherche plus d'une correspondance. Vous devrez donc affiner votre requête ou, très probablement, vérifier vos données pour voir pourquoi vous obtenez plusieurs résultats pour un numéro de client donné.

Mehmet Aras
la source
5
Use FirstOrDefault insted of SingleOrDefault..

SingleOrDefault renvoie un élément SINGLE ou null si aucun élément n'est trouvé. Si 2 éléments sont trouvés dans votre Enumerable, il lève l'exception que vous voyez

FirstOrDefault renvoie le PREMIER élément qu'il trouve ou nul si aucun élément n'est trouvé. donc s'il y a 2 éléments qui correspondent à votre prédicat, le second est ignoré

   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
la source
1

Pour info, vous pouvez également obtenir cette erreur si EF Migrations tente de s'exécuter sans Db configuré, par exemple dans un projet de test.

J'ai chassé cela pendant des heures avant de comprendre qu'il s'agissait d'une erreur sur une requête, mais pas à cause de la requête, mais parce que c'était lorsque Migrations a démarré pour essayer de créer la base de données.

Chris Moschini
la source
0

Comme le souligne @Mehmet, si votre résultat renvoie plus d'un élément, vous devez examiner vos données car je soupçonne que ce n'est pas par conception que vous avez des clients partageant un numéro personnalisé.

Mais au point que je voulais vous donner un bref aperçu.

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

pour plus d'expressions Linq, jetez un œil à System.Linq.Expressions

Martin Sax
la source