C# 当其中返回0行时,LINQ查询null异常
我有下面的LINQ方法,它按预期工作,除非没有找到行,否则我会得到一个Null异常。如果出现这种情况,我正在努力修改它以返回0C# 当其中返回0行时,LINQ查询null异常,c#,.net,linq,linq-to-sql,.net-3.5,C#,.net,Linq,Linq To Sql,.net 3.5,我有下面的LINQ方法,它按预期工作,除非没有找到行,否则我会得到一个Null异常。如果出现这种情况,我正在努力修改它以返回0 public static int GetLastInvoiceNumber(int empNumber) { using (var context = new CmoDataContext(Settings.Default.LaCrosse_CMOConnectionString)) { cont
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)))
);
}
}
你正在使用
.Where(...)
.DefaultIfEmpty()
也就是说,如果没有结果,就假设它是一个带有单个空结果的序列。然后尝试在Max调用中使用该空结果
您可能可以将其更改为:
return tGreenSheet.Where(gs => ...)
.Max(gs => (int?) Convert.ToInt32(...)) ?? 0;
这使用重载查找int?
值的最大值,并返回int?如果没有值,则为null。??0
然后将该空值转换为0。至少,这是LINQ对对象的行为。。。你必须检查它是否给你同样的结果
当然,您不需要使用??0
如果您愿意将方法签名改为返回int?
。这将提供额外的信息,因为调用方随后可以区分“无数据”和“最大值为0的某些数据”之间的差异:
另一个选项是使用DefaultIfEmpty()
的重载,该重载接受一个值,如下所示:
return tGreenSheet.Where(gs => ...)
.Select(gs => Convert.ToInt32(...))
.DefaultIfEmpty(0)
.Max();
在这样的情况下,可能有匹配项,也可能没有匹配项,我更喜欢返回对象而不是值类型。如果您返回一个值类型,您必须对值的含义有一些语义,即“这里什么都没有”。我会将其更改为返回最后一张发票,然后(当它不为null时)从发票中获取发票号。向类添加一个方法以从字符串返回数字发票号
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)); }
}
...
}
我对IQueryable
和NHibernate有着非常相似的经历。我的解决方案:
public static TExpr MaxOrDefault<TItem, TExpr>(this IQueryable<TItem> query,
Expression<Func<TItem, TExpr>> expression) {
return query.OrderByDescending(expression).Select(expression).FirstOrDefault();
}
public static TExpr MaxOrDefault(此IQueryable查询,
表达式(表达式){
返回query.OrderByDescending(表达式).Select(表达式).FirstOrDefault();
}
唯一的缺点是您一直使用标准默认值,而不是指定一个。我建议您将LINQ查询拆分为单个方法调用,以找出问题所在。我想我更喜欢从方法返回一个int?
,而不是使用一个神奇的值来表示不匹配。@tvanfosson:通常我也会这样做,但我试图匹配OP的要求。将进行编辑以表明这一点。我可以返回int?
,但我无法以那种方式编译它。我得到了这个错误8'System.Linq.IQueryable'不包含'Max'的定义和最佳扩展方法重载'System.Linq.Enumerable.Max(System.Collections.Generic.IEnumerable,System.Func)'有一些无效参数
@RefractedPaladin:Doh,类型参数的数目错误。将修复。@RefractedPaladin:Edited-查看是否有帮助。
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...
}
public static TExpr MaxOrDefault<TItem, TExpr>(this IQueryable<TItem> query,
Expression<Func<TItem, TExpr>> expression) {
return query.OrderByDescending(expression).Select(expression).FirstOrDefault();
}