【问题标题】:Linq query NOT returning null when empty空时Linq查询不返回null
【发布时间】:2018-03-05 13:58:39
【问题描述】:

我正在使用 .NetCore 1.1.2。当我将生成的操作用于GET 操作时,它应该在数据库上找不到任何内容时返回 null,但 Null 验证不起作用。

我尝试使用 Single() 而不是 SingleOrDefault 并使用 try catch 来处理抛出的异常,但这似乎不是一个优雅的解决方案。

也许是 .net 版本?

public IActionResult Success(string token)
{
    var paymentMade = _context.Payments
            .SingleOrDefaultAsync(m => m.StripeToken == token);

    if (paymentMade == null)
    {
        return NotFound(); //this never gets fired when empty
    }

    return View();
}

【问题讨论】:

  • 我想你在 FirstOrDefault 之后?
  • 您是如何定义付款的?
  • 嘿,不要使用Async - 检查paymentMate 变量的类型。使用同步版本或await
  • FirstOrDefault@user12345 相同
  • 你正在使用异步版本,而不是等待它。

标签: c# .net linq asp.net-core


【解决方案1】:

您当前的方法存在两个问题。一个是您选择的方法,另一个是您尝试在同步上下文中使用它,即使它是异步的。

首先SingleOrDefaultAsync和其他异步方法一样,不返回任何有用的值,而是Task,这是一个代表异步操作的对象。要获得上述操作的结果,您必须await它。

为此,您应该使您的方法异步或同步运行任务(不推荐,因为它会阻塞线程直到它完成)。或者,您也可以简单地使用该方法的同步版本SingleOrDefault

修改为异步的方法如下所示:

public async Task<IActionResult> Success(string token)
{
    var paymentMade = await _context.Payments.SingleOrDefaultAsync(m => m.StripeToken == token);

    if (paymentMade == null)
    {
        return NotFound();
    }

    return View();
}

同步运行任务如下所示:

public IActionResult Success(string token)
{
    var paymentMade = _context.Payments.SingleOrDefaultAsync(m => m.StripeToken == token).Result;

    if (paymentMade == null)
    {
        return NotFound();
    }

    return View();
}

但是,您可能会遇到另一个问题。根据数据类型,SingleOrDefault 和其他此类方法(如 FirstOrDefault)可能永远返回 null。对于所有不可为空的内置类型(例如布尔值、整数等)都是这种情况。如果您想要一种适用于所有情况的替代方法,那么 try-catch 是您最好的选择:

try
{
    var paymentMade =  _context.Payments.First(m => m.StripeToken == token);
}
catch (InvalidOperationException)
{
    return NotFound();
}

如果你不想这样做,那么考虑像这样拆分:

var temp = _context.Payments.Where(m => m.StripeToken == token);
if (!temp.Count == 0)
{
    return NotFound();
}

【讨论】:

    【解决方案2】:

    这是因为SingleOrDefaultAsync实际上是返回任务。你应该这样做。

    public async Task<IActionResult> Success(string token)
    {
    
        var paymentMade = await _context.Payments
            .SingleOrDefaultAsync(m => m.StripeToken == token);
    
        if (paymentMade == null)
        {
            return NotFound(); //this never gets fired when empty
        }
    
        return View();
    }
    

    【讨论】:

      【解决方案3】:

      如果您不想要列表,请尝试使用 FirstOrDefault,而不是 SingleOrDefault,并且取决于对象 paymentMade 的数据类型。

      如果您想要一个列表,请使用 .Where(m => m.StripeToken == token).ToList(),并在您的 if verify paymentMade.Count==0 中。

      看看这个LINQ: When to use SingleOrDefault vs. FirstOrDefault() with filtering criteria

      【讨论】:

        【解决方案4】:

        您正在使用 SingleOrDefault()async 版本:SingleOrDefaultAsync(),并且没有“等待”它,因此您在 paymentMade 变量中实际拥有的是一个等待对象,它不会是无所谓。

        有几种方法可以解决:

        1- 你做你的动作async 并使用await,像这样:

        public async IActionResult Success(string token)
        {
            var paymentMade = await _context.Payments
                .SingleOrDefaultAsync(m => m.StripeToken == token);
        
            if (paymentMade == null)
            {
                return NotFound(); //this never gets fired when empty
            }
        
            return View();
        }
        

        2- 您可以调用SingleOrDefault() 方法的非异步(标准)版本,您的代码将如下所示:

        public IActionResult Success(string token)
        {
            var paymentMade = _context.Payments
                .SingleOrDefault(m => m.StripeToken == token);
        
            if (paymentMade == null)
            {
                return NotFound(); //this never gets fired when empty
            }
        
            return View();
        }
        

        选择最适合你的那个

        【讨论】:

        • 你最后一个例子和另一个一样
        • 你仍然需要删除那个等待
        猜你喜欢
        • 1970-01-01
        • 2017-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-19
        • 2022-08-09
        相关资源
        最近更新 更多