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

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что будет успешным, независимо от того, сколько элементов в коллекции.

JaredPar
источник
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

Мартин Сакс
источник