Sequenz enthält mehr als ein Element

110

Ich habe einige Probleme damit, eine Liste vom Typ "RhsTruck" über Linq abzurufen und zur Anzeige zu bringen.

RhsTruck hat nur Eigenschaften Make, Model, Serial etc ... RhsCustomer hat Eigenschaften CustomerName, CustomerAddress, etc ...

Ich erhalte immer wieder die Fehlermeldung "Sequenz enthält mehr als ein Element". Irgendwelche Ideen? Nähere ich mich dem falsch?

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
quelle
1
Verwenden Sie take <> , genau wie bei der SQL Top () - Aggregatfunktion,.Take(1).SingleOrDefault();
Thein

Antworten:

254

Das Problem ist, dass Sie verwenden SingleOrDefault. Diese Methode ist nur erfolgreich, wenn die Sammlungen genau 0 oder 1 Element enthalten. Ich glaube, Sie suchen, FirstOrDefaultwelche erfolgreich sein werden, egal wie viele Elemente in der Sammlung sind.

JaredPar
quelle
8
Calvin, in diesem Fall sollten Sie diese Antwort als Lösung akzeptieren
Dejan Milicic
24
-1 "Das Problem ist, dass Sie SingleOrDefault verwenden" - soweit ich das beurteilen kann, sucht das OP nach einer Kunden-ID, die (ich nehme an) eindeutig sein sollte, daher SingleOrDefaulteigentlich besser geeignet ist als FirstOrDefault. Dies hat auch ein ernsthafteres Problem mit dem Datenbankdesign des OP aufgeworfen, da es zeigt, dass es möglich ist, 2 Kunden mit derselben ID hinzuzufügen!
James
27
@James, das OP gab an, dass meine Antwort korrekt war und die Ausnahme eindeutig besagt, dass die Sammlung mehr als ein Element enthält, das verhindert, dass sie SingleOrDefaultjemals funktioniert. Es mag zwar möglich sein, hier ein besseres Datenbankdesign zu haben, aber das scheint angemessener als Kommentar zum OP und nicht als -1 für eine Antwort.
JaredPar
9
IMO ist das zugrunde liegende Problem letztendlich das DB-Design, da es zeigt, dass der Datenbank zwei eindeutige Kunden-IDs hinzugefügt werden können. SingleOrDefaultlöst eine Ausnahme aus, da eine Inkonsistenz zwischen dem, was die Methode erwartet, und dem, was sie findet, besteht. Obwohl Ihre Antwort die Ausnahme stoppt, löst sie für mich nicht das Problem, sondern eher eine Karte, mit der Sie das Gefängnis verlassen können, daher die -1.
James
2
Das ist irreführend! Die Verwendung für SingleOrDefaultdann fällt in, wenn Sie erwarten, dass eine Sammlung 0 oder 1 Elemente enthält und Sie überprüfen möchten, dass dies jedes Mal passiert ...
Achilles
23

SingleOrDefaultMethode löst ein aus, Exceptionwenn die Sequenz mehr als ein Element enthält.

Anscheinend ist Ihre Anfrage in GetCustomer mehr als eine Übereinstimmung. Sie müssen also entweder Ihre Abfrage verfeinern oder höchstwahrscheinlich Ihre Daten überprüfen, um festzustellen, warum Sie für eine bestimmte Kundennummer mehrere Ergebnisse erhalten.

Mehmet Aras
quelle
5
Use FirstOrDefault insted of SingleOrDefault..

SingleOrDefault gibt ein SINGLE-Element oder null zurück, wenn kein Element gefunden wird. Wenn in Ihrem Enumerable 2 Elemente gefunden werden, wird die angezeigte Ausnahme ausgelöst

FirstOrDefault gibt das gefundene FIRST-Element zurück oder null, wenn kein Element gefunden wird. Wenn es also 2 Elemente gibt, die Ihrem Prädikat entsprechen, wird das zweite ignoriert

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

Zu Ihrer Information, Sie können diesen Fehler auch erhalten, wenn EF Migrations versucht, ohne konfigurierte Datenbank auszuführen, z. B. in einem Testprojekt.

Verfolgte dies stundenlang, bevor ich herausfand, dass es bei einer Abfrage fehlerhaft war, aber nicht wegen der Abfrage, sondern weil Migrations aktiv wurde, um zu versuchen, die Datenbank zu erstellen.

Chris Moschini
quelle
0

Wie @Mehmet hervorhebt, müssen Sie, wenn Ihr Ergebnis mehr als 1 Element zurückgibt, Ihre Daten untersuchen, da ich vermute, dass es nicht beabsichtigt ist, dass Kunden eine Kundennummer teilen.

Aber bis zu dem Punkt wollte ich Ihnen einen schnellen Überblick geben.

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

Weitere Linq-Ausdrücke finden Sie unter System.Linq.Expressions

Martin Sax
quelle