空的linq查询结果异常

时间:2018-10-08 06:56:05

标签: c# mysql asp.net-mvc linq

我正在尝试向我的MVC应用程序添加过滤器。我在这方面有些成功,因为如果它存在于数据库中,我可以返回一个过滤后的值。

但是,当它不存在于数据库中时,我希望它返回一个空列表。因为如果结果为零,Linq应该返回空。但是,如果由于某种原因代码语句失败,并且由于输入的字段与任何数据库条目不匹配,我都使用try catch来捕获任何异常,而linq查询会陷入catch且异常为null。

我不知道这是怎么回事,它甚至不应该陷入困境。

Linq查询:

 if (attr1 == "null" && attr3 != "null" && attr2 != "null")
    {
       attr1 = "%";

         Size = db.GetFilterResultCount(index, Size, attr1, attr2, attr3).Count();
         accountlist = db.GetFilterResult(index, Size, attr1, attr2, attr3).ToList();

         filteredlist.GetList = accountlist;
         filteredlist.index = index;
         filteredlist.size = Size;
         filteredlist.totalSize = db.Accounts.Count();
         filteredlist.resultSize = db.GetFilterResultCount(index, Size, attr1, attr2, attr3).Count();
    }

这是我用来检查要过滤哪个字段的许多条件之一。但是linq查询对于所有这些查询都是相同的。

存储过程:

    CREATE PROCEDURE [dbo].[GetFilterResult]
@PageIndex INT,  
@pageSize INT,
@attr1 nvarchar(300),
@attr2 nvarchar(300),
@attr3 nvarchar(300)

    AS
    Begin
    SELECT  Accounts.firstName, Accounts.lastName, Accounts.Email, 
     Accounts.dateOfBirth, Accounts.phoneNo, Countries.CountryName 

    FROM Accounts INNER JOIN Countries On Accounts.CountryID = 
     Countries.CountryID

    Where (Accounts.firstName LIKE CONCAT('%', @attr1, '%') and 
     Accounts.lastName LIKE CONCAT('%', @attr2, '%') and Accounts.CountryID 
      Like CONCAT('%', @attr3, '%')) 

    ORDER BY UserId OFFSET @PageSize*(@PageIndex-1) ROWS FETCH NEXT 
     @PageSize ROWS ONLY;

    END

GetFilterResultCount:

   CREATE PROCEDURE [dbo].[GetFilterResult]
@PageIndex INT,  
@pageSize INT,
@attr1 nvarchar(300),
@attr2 nvarchar(300),
@attr3 nvarchar(300)

    AS
    Begin
    SELECT  Accounts.firstName, Accounts.lastName, Accounts.Email, 
     Accounts.dateOfBirth, Accounts.phoneNo, Countries.CountryName 

    FROM Accounts INNER JOIN Countries On Accounts.CountryID = 
     Countries.CountryID

    Where (Accounts.firstName LIKE CONCAT('%', @attr1, '%') and 
     Accounts.lastName LIKE CONCAT('%', @attr2, '%') and Accounts.CountryID 
      Like CONCAT('%', @attr3, '%')) 


    END

3 个答案:

答案 0 :(得分:0)

这不是您的答案,但是当attr1 ==“ null”时,您尝试忽略attr1 where子句。您可以在查询中使用IFNULL函数

Where (Accounts.firstName LIKE  CONCAT('%', IFNULL(@attr1, Accounts.firstName), '%') and

并将null传递给存储过程

   attr1 = null;
   accountlist = db.GetFilterResult(index, Size, attr1, attr2, attr3).ToList();

答案 1 :(得分:0)

我发现了问题。尝试捕获无法正常工作,我将其删除,并立即收到一个异常消息:“返回的结果不能小于1”或类似的内容。因此,基本上因为该行,结果至少需要1行以上。

    ORDER BY UserId OFFSET @PageSize*(@PageIndex-1) ROWS FETCH NEXT 
 @PageSize ROWS ONLY;

因此,我添加了一个条件,该条件首先检查结果大小,如果结果为零而不是使用上面的存储过程返回,我只是返回了一个空列表。

答案 2 :(得分:0)

您的存储过程是一个简单的SQL选择。这意味着如果没有任何项目与您的SQL WHERE相匹配,则存储过程将返回一个空列表。

您忘记告诉您db的类型,尤其是db.GetFilterResult的类型。您是自己制作的,还是您的db类很聪明,它会自动知道要调用哪个存储过程。

如果您自己创建它,它将类似于:

IEnumerable<Account> GetFilterResultCount(...)
{
     try
     {
          var fetchedData = CallStoredProcedure();
          foreach(var fetchedRow in fetchedData)
          {
              // use fetched data to create a new account object
              Account account = new Account() {... use fetchedData }
              yield return account;
          }
     }
     catch (Exception exc)
     {
         // TODO: decide what to do with this exception. Log and continue?
         // return empty sequence as if no Accounts where available
     }
}

如果存储过程返回空选择或异常,则它将返回空序列。如果对存储过程的调用返回null(如果未选择任何内容(非常不寻常)),则应检查是否返回null:

 var fetchedData = CallStoredProcedure();
 if (fetchedData != null)
 {
     foreach(var fetchedRow in fetchedData) ...

有些人不喜欢使用yield并更喜欢仅使用LINQ(尽管LINQ内部产生)。

try
{
    var fetchedData = CallStoredProcedure();
    if (fetchedData == null)
    {   // nothing fetched, return empty sequence
        return Enumerable.Empty<Account>();
    }
    else
    {
         return fetchedData.Select(fetchedRow => new Account() {...};
    }
}
catch (Exception exc)
{   // problem fetching data, return empty sequence
    return Enumerable.Empty<Account>();
}

如果您熟悉yield return,那么我不确定LINQ解决方案是否更具可读性/可维护性。

用法:

var accountlist = db.GetFilterResult(index, Size, attr1, attr2, attr3)
    .ToList();

如果您不能更改db.GetFilterResult,我想最好是自己编写

IEnumerable<Account> FetchFilterResultData(...)
{
     var fetchedData = db.GetFilterResult(...);
     // return emtpy sequence if null returned:
     return fetchedData ?? Enummerable.Empty<Account>();

     // TODO: exception handling needed?
}

用法:

var accountlist = this.FetchFilterResultData(index, Size, attr1, attr2, attr3)
    .ToList();