【问题标题】:Filter data from database by passing multiple nullable values通过传递多个可为空的值从数据库中过滤数据
【发布时间】:2021-07-04 14:47:33
【问题描述】:

我有一个包含 n 个列的表,我想按 n 个可空参数过滤数据, 如果 else 条件有任何方法可以在 c#(Linq,Entity 框架)或带有查询的 SQL 中解决这个问题,而不是写 n 次。 如果有人有任何解决方案,请举例说明解决方案。 谢谢你。

【问题讨论】:

  • 您是希望代码搜索空值,还是希望代码允许 2 个或 5 个或 10 个参数都是可选的?换句话说,您想拥有尽可能多的可选参数吗?
  • 是的,我正在为多个可选参数寻找一种简单的解决方案。
  • 好的 - 请参阅下文,了解如何解决此问题

标签: c# sql asp.net database


【解决方案1】:

我可以在 SQL 语句和 LINQ 查询中使用的很好的“技巧”是允许查询参数为空,然后检查每个参数的匹配值或空。

我们使我们的参数可以为空,并根据它们各自的字段/属性或为空来检查每个参数。

基本上,我们告诉查询向我们提供输入参数与属性值匹配的所有记录这有效地提供了一个参数,当它为 null 时被视为可选,否则不是可选的。

使用此方法可以轻松添加更多可选参数。

IList<ThingToQuery> things = new List<ThingToQuery>();
things.Add(new ThingToQuery(){ Property1 = "Thing1", Property2 = 100, Property3 = new DateTime(2001,1,1)});
things.Add(new ThingToQuery() { Property1 = "Thing2", Property2 = 100, Property3 = new DateTime(2002, 2, 2) });
things.Add(new ThingToQuery() { Property1 = "Thing3", Property2 = 300, Property3 = new DateTime(2003, 3, 3) });

// query sample #1 - prepare params
string queryParam1 = "Thing1";
int? queryParam2 = 100;
DateTime? queryParam3 = null;

// in our query we check for a matching value or if the param is null
List<ThingToQuery> results = things.Where(t => (t.Property1 == queryParam1 || queryParam1 == null)
                                          && (t.Property2 == queryParam2 || queryParam2 == null)
                                          && (t.Property3 == queryParam3 || queryParam3 == null)
            ).ToList();

// query sample #1 results
// Thing1, 100, 1/1/2001 12:00:00 AM

// query sample #2 - prepare params
string queryParam1 = null;
int? queryParam2 = 100;
DateTime? queryParam3 = null;

// query sample #2 results
// Thing1, 100, 1/1/2001 12:00:00 AM
// Thing2, 100, 2/2/2002 12:00:00 AM

一个简单的 SQL 示例...

SELECT * FROM Users u
    WHERE (u.UserName = @UserName OR @UserName IS NULL)
    OR (u.FavoriteColor = @FavColor OR @FavColor IS NULL)

【讨论】:

  • 您确实避免了字符串连接,但是对于每个新参数,我们只需要进入代码并添加一个 if/then 代码块。对于您拥有的每个参数,您必须修改原始 sql 查询文本 - 代码中的两个位置。对于每个参数,您必须包括条件和@Parm = null 测试。所以你编辑两个地方,每个参数都有双重条件。因此,每种方法都需要权衡取舍。使用 20 个参数,您就有 40 个条件,在大多数情况下,它们中的大多数都没有被使用。因此,需要权衡取舍 - 没有一种解决方案是唯一的答案。
  • @AlbertD.Kallal “没有一个解决方案是唯一的答案。”,正确,这就是我发布答案的原因。它并不完美,可以改进,事实仍然是我成功地使用了这种方法。所以,有了它的“不完美”,它仍然是一个有效的选择。
  • @AlbertD.Kallal 我想我明白你为什么发表评论了。当我提到“动态 WHERE 子句构建”时,我并不是要暗示我的答案更好。我已从答案中删除了该行。
  • 不用担心 - 每个人都应该 100% 感到自己的情况。我的意思是你加入进来,花时间,提供代码,并提供帮助。我不会担心的。我的意思是,真的,这个想法和代码仍然很棒。有什么关于 SO 的帮助吗?伙计,这只是您在这里提供的黄金和宝贵的时间和知识-我们不能在 SO 上阻止这一点。与往常一样,每个人(包括我)都倾向于认为我们的方式是最好的方式 - 有 100 种方法可以剥去这只猫的皮 - 你的观点、你的想法和你的贡献都是独立的。不用担心 - 一点也不担心!
【解决方案2】:

当然,您可以在该 sql 中包含可选参数。

你这样做的方式?您不在 sql 中包含参数,然后仅根据需要添加参数!这样,您就不需要在作为条件的 sql 中的所有这些额外条件,然后还需要对 @Param = null 的测试。

因此,假设我可以搜索城市或城市 + 酒店名称。并让我们折腾 [x] 仅搜索活动酒店。或者我们只搜索 Hotelname。或所有 3 个值!

正如您注意到的那样,这变成了一个只需要处理 3 个选择(6 个可能的排列)的参数集。我只能想象如果你有 5 或 6 个可能的和可选的值,这会变得多么糟糕。

那么,简单的解决方案?好吧,我们将 sql 拆分为基本查询,然后动态添加参数。我们仍然想要(并获得)强类型参数检查,从而获得 sql 注入保护,这当然是这里的一个重要目标。

因此我们有这样的设置:

然后搜索会这样做:

public void loadgrid()
{
string strSQL;
string strWhere;
strSQL = "select ID, FirstName, LastName, HotelName, City, Province from tblHotels";
strWhere = "";

using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.Test3)))
{
    if (txtHotelName.Text != "")
    {
        // search for hotel name
        strWhere = "(HotelName = @HotelName)";
        cmdSQL.Parameters.Add("@HotelName", SqlDbType.NVarChar).Value = txtHotelName.Text;
    }

    if (txtCity.Text != "")
    {
        if (strWhere != "")
            strWhere += " AND ";
        strWhere += "(City = @City)";
        cmdSQL.Parameters.Add("@City", SqlDbType.NVarChar).Value = txtCity.Text;
    }

    if (chkOnlyActive.Checked == true)
    {
        if (strWhere != "")
            strWhere += " AND ";
        strWhere += strWhere + "(HotelActive = @Active)";
        cmdSQL.Parameters.Add("@Active", SqlDbType.Bit).Value = 1;
    }

    if (strWhere != "")
        cmdSQL.CommandText = strSQL + " WHERE " + strWhere;

    cmdSQL.Connection.Open();
    DataTable rstData = new DataTable();
    rstData.Load(cmdSQL.ExecuteReader);

    ListView1.DataSource = rstData;
    ListView1.DataBind();
}
}

所以请注意我们如何简单地构建 where 子句。而且您注意到没有什么可以阻止我们更改 sql 命令文本 - 而且我们也 100% 能够动态添加参数(添加它们不会强制检查 sql - 仅在执行时。

结果呢?我们可以再添加 5 个标准。它们是可选的,它们不需要我们使用我们可能不想使用甚至不需要的大量参数进行巨大的长 sql 查询。

如上所示,我们永远不会将用户输入串联起来——它们总是只与参数值一起使用。

那么,对于任何文本框、复选框、组合框或其他什么?当它们没有填写时,我们只是忽略它们。因此它们都是可选的,并且在我们的代码中被忽略了。因此,上述设置可以让我们轻松添加 2 或 5 个更多可选参数。

注意上面,我们总是“检查” where 子句是否已经有一些值——如果是,那么我们在前面添加“AND”子句。我们可以在这里使用“OR”,但这取决于您想要的搜索类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 2022-12-06
    • 2019-09-29
    • 2016-02-18
    • 2014-10-25
    • 2020-05-04
    • 1970-01-01
    相关资源
    最近更新 更多