Entity Framework вызывает MAX на ноль для записей - PullRequest
47 голосов
/ 18 июля 2010

При вызове Max () для IQueryable и нулевых записей я получаю следующее исключение.

Приведение к типу значения 'Int32' не выполнено, поскольку материализованное значение равно нулю. Либо универсальный параметр типа результата, либо запрос должен использовать обнуляемый тип.

var version = ctx.Entries
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId)
    .Max(e => e.Version);

Теперь я понимаю, почему это происходит, мой вопрос: как лучше всего это сделать, если таблица может быть пустой? Приведенный ниже код работает и решает эту проблему, но очень уродливо, разве нет концепции MaxOrDefault ()?

int? version = ctx.Entries
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId)
    .Select(e => (int?)e.Version)
    .Max();

Ответы [ 6 ]

83 голосов
/ 18 июля 2010

Да, приведение к Nullable of T является рекомендуемым способом решения проблемы в запросах LINQ to Entities.Наличие метода MaxOrDefault (), который имеет правильную сигнатуру, звучит как интересная идея, но вам просто потребуется дополнительная версия для каждого метода, представляющего эту проблему, которая не очень хорошо масштабируется.

Это одно из многих несоответствий между тем, как вещи работают в CLR, и тем, как они работают на сервере базы данных.Подпись метода Max () была определена таким образом, поскольку ожидается, что тип результата будет точно таким же, как тип ввода в CLR.Но на сервере базы данных результат может быть нулевым.По этой причине вам необходимо преобразовать входные данные (хотя в зависимости от того, как вы пишете свой запрос, этого может быть достаточно для преобразования выходных данных) в Nullable of T.

Вот решение, которое выглядит несколько проще, чему вас есть выше:

var version = ctx.Entries 
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId) 
    .Max(e =>(int?)e.Version);

Надеюсь, это поможет.

18 голосов
/ 02 апреля 2013

Попробуйте создать значение по умолчанию для вашего максимума.

int version = ctx.Entries 
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId) 
    .Max(e =>(int?)e.Version) ?? 0;
6 голосов
/ 07 августа 2013

Вы можете написать простой метод расширения, подобный этому, он возвращает значение по умолчанию типа T, если записей не существует, и затем применяет к нему Max или запрос, если записи существуют.

public static T MaxOrEmpty<T>(this IQueryable<T> query)
{
    return query.DefaultIfEmpty().Max();
}

и вы могли бы использовать это так

maxId = context.Competition.Select(x=>x.CompetitionId).MaxOrEmpty();
2 голосов
/ 18 июля 2010

Я не могу принять «нет» за ответ :) Я проверил нижеприведенное, и он работает, я еще не проверил сгенерированный SQL, поэтому будьте осторожны, я обновлю его, как только протестирую больше.

0 голосов
/ 17 сентября 2013

а как же

query.Max<TSource,TResult?>(selector)

Я имею в виду, явно установить тип результата, чтобы быть обнуляемым

0 голосов
/ 15 апреля 2013

Попробуйте это:

IEnumerable<AlertsResultset> alerts = null;

    alerts = (from POA in SDSEntities.Context.SDS_PRODUCT_ORDER_ALERT
              join A in SDSEntities.Context.SDS_ALERT on POA.ALERT_ID equals A.ALERT_ID
              orderby POA.DATE_ADDED descending
              select new AlertsResultset
              {
                  ID = POA.PRODUCT_ORDER_ALERT_ID == null ? 0:POA.PRODUCT_ORDER_ALERT_ID ,
                  ITEM_ID = POA.ORDER_ID.HasValue ? POA.ORDER_ID.Value : POA.PRODUCT_ID.Value,
                  Date = POA.DATE_ADDED.Value,
                  orderType = SDSEntities.Context.SDS_ORDER.Where(o => o.ORDER_ID == POA.ORDER_ID.Value).FirstOrDefault().ORDER_TYPE,
                  TransactionNumber = POA.PRODUCT_ID.HasValue ? (SDSEntities.Context.SDS_PRODUCT.Where(p => p.PRODUCT_ID == POA.PRODUCT_ID.Value).FirstOrDefault().TRANSACTION_NUMBER) : (SDSEntities.Context.SDS_ORDER.Where(o => o.ORDER_ID == POA.ORDER_ID.Value).FirstOrDefault().TRANSACTION_NUMBER),
                  Publisher = POA.PRODUCT_ID.HasValue ?
                  (
                  SDSEntities.Context.SDS_PRODUCT.Where(p => p.PRODUCT_ID == POA.PRODUCT_ID.Value).FirstOrDefault().PRODUCT_TYPE_NUMBER == "ISSUE" ? (from prod in SDSEntities.Context.SDS_PRODUCT
                                                                                                                                                      join ji in SDSEntities.Context.SDS_JOURNAL_ISSUE on prod.PRODUCT_ID equals ji.PRODUCT_ID
                                                                                                                                                      join j in SDSEntities.Context.SDS_JOURNAL on ji.JOURNAL_ID equals j.JOURNAL_ID
                                                                                                                                                      where prod.PRODUCT_ID == POA.PRODUCT_ID
                                                                                                                                                      select new { j.PUBLISHER_NAME }).FirstOrDefault().PUBLISHER_NAME : (from prod in SDSEntities.Context.SDS_PRODUCT
                                                                                                                                                                                                                          join bi in SDSEntities.Context.SDS_BOOK_INSTANCE on prod.PRODUCT_ID equals bi.PRODUCT_ID
                                                                                                                                                                                                                          join b in SDSEntities.Context.SDS_BOOK on bi.BOOK_ID equals b.BOOK_ID
                                                                                                                                                                                                                          where prod.PRODUCT_ID == POA.PRODUCT_ID
                                                                                                                                                                                                                          select new { b.PUBLISHER_NAME }).FirstOrDefault().PUBLISHER_NAME
                  )
                  : (SDSEntities.Context.SDS_ORDER.Where(o => o.ORDER_ID == POA.ORDER_ID.Value).FirstOrDefault().PUBLISHER_NAME),
                  Alert = A.ALERT_NAME,
                  AlertType = A.ALERT_TYPE,
                  IsFlagged = POA.IS_FLAGGED.Value,
                  Status = POA.ALERT_STATUS
              });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...