Подтвердить что ты не робот

Entity Framework, вызывающая MAX на нулевом значении

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

Недопустимое значение cast для значения 'Int32', потому что материализованное значение равно null. Либо общий параметр типа результата, либо запрос должен использовать тип с нулевым значением.

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();
4b9b3361

Ответ 1

Да, приведение в Nullable от 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);

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

Ответ 2

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

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

Ответ 3

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

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

и вы можете использовать его так:

maxId = context.Competition.Select(x=>x.CompetitionId).MaxOrEmpty();

Ответ 4

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

var test = ctx.Entries
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId)
    .MaxOrDefault(x => x.Version);

public static TResult? MaxOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
    where TResult : struct
{
    return source
        .Select(selector)
        .Cast<TResult?>()
        .Max();
}

Ответ 5

Попробуйте следующее:

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
              });

Ответ 6

как насчет

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

менее уродливо, более элегантно