实体框架在记录上调用MAX为null

时间:2010-07-18 03:25:45

标签: entity-framework

在IQueryable上调用Max()并且没有记录时,我得到以下异常。

转换为值类型“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();

9 个答案:

答案 0 :(得分:82)

是的,强制转换为Nullable of T是处理LINQ to Entities查询中问题的推荐方法。拥有一个具有正确签名的MaxOrDefault()方法听起来像一个有趣的想法,但是你只需要为每个提出这个问题的方法提供一个额外的版本,这个版本不能很好地扩展。

这是CLR中的工作方式与它们在数据库服务器上的实际工作方式之间的许多不匹配之一。 Max()方法的签名已经这样定义,因为结果类型应该与CLR上的输入类型完全相同。但是在数据库服务器上,结果可以为null。出于这个原因,您需要将输入(尽管取决于您编写查询的方式,将输出强制转换为输出)转换为Nullable of T.

这是一个看起来比上面简单的解决方案:

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

希望这有帮助。

答案 1 :(得分:18)

尝试此操作为最大值

创建默认值
int version = ctx.Entries 
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId) 
    .Max(e =>(int?)e.Version) ?? 0;

答案 2 :(得分:6)

您可以编写一个这样的简单扩展方法,如果不存在记录,则返回类型T的默认值,然后将Max应用于该值或查询是否存在记录。

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

你可以像这样使用它

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

答案 3 :(得分:2)

我不能拒绝回答:)我已经测试了下面的内容并且它有效,我还没有检查生成的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();
}

答案 4 :(得分:0)

试试这个:

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

答案 5 :(得分:0)

怎么样

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

我的意思是明确地将结果类型设置为可为空的

答案 6 :(得分:0)

我想建议根据现有答案进行合并:

@divega答案效果很好,sql输出也很好,但是由于' d 而不是 r 重复 y 我们自己” 扩展将是更好的方法,例如 @Code唯一显示。但是此解决方案可以根据需要输出更复杂的sql。 但是您可以使用以下扩展名将两者结合在一起:

 public static int MaxOrZero<TSource>(this IQueryable<TSource> source, 
 Expression<Func<TSource, int>> selector)
        {
            var converted = Expression.Convert(selector.Body, typeof(int?));
            var typed = Expression.Lambda<Func<TSource, int?>>(converted, selector.Parameters);

            return source.Max(typed) ?? 0;
        }

答案 7 :(得分:0)

您可以使用:

ReactDOMServer.renderToString(React.createElement(DivComponent));

答案 8 :(得分:-1)

您可以使用try / catch并编写扩展:

public static class QueryableExtensions
{
    public static TResult? MaxOrDefault<T, TResult>(this IQueryable<T> query, Expression<Func<T, TResult>> selector) where TResult : struct
    {
        try
        {
            return query.Max(selector);
        }
        catch
        {
            return null;
        }
    }
}

并按以下方式使用它:

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