我有以下LINQ方法按预期工作,除非找到No Rows,然后我得到Null Exception。我正在努力如何修改它以返回0,如果发生这种情况。
public static int GetLastInvoiceNumber(int empNumber)
{
using (var context = new CmoDataContext(Settings.Default.LaCrosse_CMOConnectionString))
{
context.Log = Console.Out;
IQueryable<tblGreenSheet> tGreenSheet = context.GetTable<tblGreenSheet>();
return (tGreenSheet
.Where(gs => gs.InvoiceNumber.Substring(2, 4) == empNumber.ToString())
.DefaultIfEmpty()
.Max(gs => Convert.ToInt32(gs.InvoiceNumber.Substring(6, gs.InvoiceNumber.Length)))
);
}
}
由于
我在下面尝试了Jon Skeet的一个建议,现在我得到了Unsupported overload used for query operator 'DefaultIfEmpty'
public static int GetLastInvoiceNumber(int empNumber)
{
using (var context = new CmoDataContext(Settings.Default.LaCrosse_CMOConnectionString))
{
context.Log = Console.Out;
IQueryable<tblGreenSheet> tGreenSheet = context.GetTable<tblGreenSheet>();
return tGreenSheet
.Where(gs => gs.InvoiceNumber.Substring(2, 4) == empNumber.ToString())
.Select(gs => Convert.ToInt32(gs.InvoiceNumber.Substring(6, gs.InvoiceNumber.Length)))
.DefaultIfEmpty(0)
.Max();
}
}
答案 0 :(得分:11)
你正在使用
.Where(...)
.DefaultIfEmpty()
表示如果没有结果,则假装它是具有单个null结果的序列。然后,您尝试在Max调用中使用该null结果...
您可以将其更改为:
return tGreenSheet.Where(gs => ...)
.Max(gs => (int?) Convert.ToInt32(...)) ?? 0;
这使用重载找到int?
值的最大值 - 如果没有值,则返回int? null
。 ?? 0
然后将该空值转换为0.至少,这是LINQ to Objects行为......您必须检查它是否为您提供相同的结果。
当然,如果您愿意更改方法签名以返回?? 0
,则无需使用int?
。这将提供额外的信息,因为调用者可以告诉“无数据”和“最大值为0的某些数据”之间的区别:
return tGreenSheet.Where(gs => ...)
.Max(gs => (int?) Convert.ToInt32(...));
另一种选择是使用DefaultIfEmpty()
的重载来获取值 - 如下所示:
return tGreenSheet.Where(gs => ...)
.Select(gs => Convert.ToInt32(...))
.DefaultIfEmpty(0)
.Max();
答案 1 :(得分:0)
在这种情况下,当可能存在或不存在匹配项时,我更喜欢返回对象而不是值类型。如果你返回一个值类型,你必须有一些关于什么值意味着“这里没有任何东西”的语义。我会将其更改为返回最后一张发票,然后(当它为非空时)从发票中获取发票号。在类中添加一个方法,以便从字符串中返回数字发票号。
public static tbleGreenSheet GetLastInvoice(int empNumber)
{
using (var context = new CmoDataContext(Settings.Default.LaCrosse_CMOConnectionString))
{
context.Log = Console.Out;
return context.GetTable<tblGreenSheet>()
.Where(gs => gs.InvoiceNumber.Substring(2, 4) == empNumber.ToString())
.OrderByDescending(gs => Convert.ToInt32(gs.InvoiceNumber.Substring(6, gs.InvoiceNumber.Length)))
.FirstOrDefault();
}
}
public class tbleGreenSheet
{
....
public int NumericInvoice
{
get { return Convert.ToInt32(InvoiceNumber.Substring(6, InvoiceNumber.Length)); }
}
...
}
用作
var invoice = Foo.GetLastInvoice( 32 );
if (invoice != null)
{
var invoiceNumber = invoice.NumericInvoice;
...do something...
}
else
{
...do something else...
}
答案 2 :(得分:0)
我与IQueryable<T>
和NHibernate的体验非常相似。我的解决方案:
public static TExpr MaxOrDefault<TItem, TExpr>(this IQueryable<TItem> query,
Expression<Func<TItem, TExpr>> expression) {
return query.OrderByDescending(expression).Select(expression).FirstOrDefault();
}
唯一的缺点是你被标准的默认值所困,而不是指定一个。