Последовательность содержит более одного элемента


111

У меня возникли проблемы с получением списка типа "RhsTruck" через Linq и его отображением.

RhsTruck имеет только свойства Make, Model, Serial и т. Д. RhsCustomer имеет свойства CustomerName, CustomerAddress и т. Д.

Я все время получаю ошибку «Последовательность содержит более одного элемента». Любые идеи? Я неправильно подхожу к этому?

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
Используйте take <> , то же самое с агрегатной функцией SQL Top () ,.Take(1).SingleOrDefault();
Thein

Ответы:


255

Проблема в том, что вы используете SingleOrDefault. Этот метод будет успешным только тогда, когда коллекции содержат ровно 0 или 1 элемент. Я считаю, что вы ищете то, FirstOrDefaultчто будет успешным, независимо от того, сколько элементов в коллекции.


8
Кальвин, в таком случае вы должны принять этот ответ как решение
Деян Миличич

24
-1 «Проблема в том, что вы используете SingleOrDefault» - насколько я могу судить, OP ищет идентификатор клиента, который (я предполагаю) должен быть уникальным, поэтому на SingleOrDefaultсамом деле более уместен, чем FirstOrDefault. Кроме того, это на самом деле подняло более серьезную проблему с дизайном базы данных OP, поскольку показывает, что можно добавить 2 клиентов с одинаковым идентификатором!
Джеймс

27
@James, OP заявил, что мой ответ был правильным, и в исключении четко указано, что в коллекции есть более одного элемента, который не позволяет SingleOrDefaultкогда-либо работать. Верно, что здесь можно было бы иметь лучший дизайн базы данных, но это кажется более подходящим в качестве комментария к OP, а не -1 в ответе.
JaredPar

9
IMO основная проблема - это, в конечном итоге, дизайн БД, поскольку он показывает, что в базу данных можно добавить 2 уникальных идентификатора клиента. SingleOrDefaultгенерирует исключение, потому что существует несоответствие между тем, что ожидает метод, и тем, что он обнаруживает. Таким образом, хотя ваш ответ останавливает исключение, для меня он на самом деле не решает проблему, это скорее карта «выйти из тюрьмы бесплатно», отсюда и -1.
Джеймс

2
Это заблуждение! Использование для SingleOrDefaultthen относится к случаям, когда вы ожидаете, что в коллекции будет 0 или 1 элемент, и вы хотите проверять, что это происходит каждый раз ...
Ахилл

24

SingleOrDefaultгенерирует, Exceptionесли в последовательности более одного элемента.

Очевидно, ваш запрос в GetCustomerобнаруживает более одного совпадения. Таким образом, вам нужно будет либо уточнить свой запрос, либо, скорее всего, проверить свои данные, чтобы понять, почему вы получаете несколько результатов для данного номера клиента.


5
Use FirstOrDefault insted of SingleOrDefault..

SingleOrDefault возвращает SINGLE элемент или null, если элемент не найден. Если в вашем Enumerable обнаружены 2 элемента, он выдает исключение, которое вы видите

FirstOrDefault возвращает ПЕРВЫЙ найденный элемент или null, если элемент не найден. поэтому, если есть 2 элемента, которые соответствуют вашему предикату, второй игнорируется

   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

К вашему сведению, вы также можете получить эту ошибку, если EF Migrations пытается запустить без настроенной базы данных, например, в тестовом проекте.

Преследовал это в течение нескольких часов, прежде чем я понял, что это была ошибка в запросе, но не из-за запроса, а потому, что это произошло, когда Migrations запустил, чтобы попытаться создать Db.


0

Как указывает @Mehmet, если ваш результат возвращает более одного сообщения, вам необходимо изучить ваши данные, поскольку я подозреваю, что у вас есть клиенты, разделяющие номер клиента, не по дизайну.

Но я хотел дать вам краткий обзор.

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

для получения дополнительных выражений Linq посмотрите System.Linq.Expressions

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.