可查询的 WHERE 包含 String、Int、DateTime
Queryable WHERE Contains String, Int, DateTime
我正在处理这行代码:
query = query.Where(p =>
p.ChckNumber.ToString().Contains(globalSearch.ToString()) ||
p.BankAccount.ToString().Contains(globalSearch.ToString()) ||
p.Description.ToString().Contains(globalSearch.ToString()) ||
p.CheckAmount.ToString().Contains(globalSearch) ||
p.ClearedDate.ToString().Contains(globalSearch.ToString()) ||
p.SentDate.ToString().Contains(globalSearch.ToString()));
使用这行代码,我基本上是在进行搜索,当 globalSearch
是 string
并且像 BankAccount
和 Description
这样的列时,它似乎工作正常是 varchar
,但是,当 globalSearch
是 Int
或 DateTime
(-2233 或 4/9/2013)时,对于列 CheckAmount (int)
、ClearedDate (DateTime)
, SentDate (DateTime)
, 它 return 0 行,如果 globalSearch
匹配 ChckNumber
中的 int
它有效!
我做错了什么?
我运行这个查询在SQL服务器:
SELECT CONVERT(VARCHAR(MAX), ClearedDate) FROM myTable
和我所有的日期 return 2017 年 9 月 9 日 如果 globalSearch
是 2017 年 9 月 10 日,它可以工作,但它不适用于我需要的格式:9/9/2017
您不应该关心 globalSearch 是否是 Int,因为您应该始终将它转换为字符串,除非是 DateTime,并且您不应该关心列是 varchar 还是 Int,因为您总是将列转换为字符串,除非 DateTime.
注意,根据您的评论,我假设您只比较月、日和年,并不关心 ClearedDate 的时间
我发现您的代码存在三个潜在问题:
- 您没有将 globalSearch 转换为 CheckAmount 列的字符串
- 您在调用 .ToString 之前没有检查任何列的空值,也许您的所有列都不允许空值
- 您的代码可读性不是很好,人眼很难发现不一致之处。
这里是每次都将 globalSearch 转换为字符串的更具可读性的代码,因为同样,您不会将 globalSearch 转换为 CheckAmount 的字符串:
var gsStr = globalSearch.ToString();
var gsDate = DateTime.MinDate;
if(globalSearch.GetType() == typeof(DateTime))
{
gsDate = globalSearch;
}
query = query.Where(p => p.ChckNumber.ToString().Contains(gsStr)
|| p.BankAccount.ToString().Contains(gsStr)
|| p.Description.ToString().Contains(gsStr)
|| p.CheckAmount.ToString().Contains(gsStr)
|| p.ClearedDate.Date == gsDate.Date
|| p.SentDate.ToString().Contains(gsStr));
如果您使用的是 C# 6.0,则可以使用新的 Null Propagation Operator 来防止错误,如果您的任何列现在或将来确实允许 null:
var gsStr = globalSearch.ToString();
var gsDate = DateTime.MinDate;
if(globalSearch.GetType() == typeof(DateTime))
{
gsDate = globalSearch;
}
query = query.Where(p => p.ChckNumber?.ToString().Contains(gsStr)
|| p.BankAccount?.ToString().Contains(gsStr)
|| p.Description?.ToString().Contains(gsStr)
|| p.CheckAmount?.ToString().Contains(gsStr)
|| p.ClearedDate?.Date == gsDate.Date
|| p.SentDate?.ToString().Contains(gsStr));
将 globalSearch ToString 转换为 CheckAmount Contains 可能会解决您的问题,使您的代码更具可读性并防止出现空值,如果它没有修复错误,则更容易调试。
您好,如果您正在寻找日期的正确格式,请试试这个。
SELECT CONVERT(VARCHAR(10), SYSDATETIME(), 103)
单字符日期格式。我们可以使用 char 作为 ToString 的参数来指定预设格式。这些是标准格式。
query = query.Where(p =>
p.ChckNumber.ToString().Contains(globalSearch.ToString()) ||
p.BankAccount.ToString().Contains(globalSearch.ToString()) ||
p.Description.ToString().Contains(globalSearch.ToString()) ||
p.CheckAmount.ToString().Contains(globalSearch) ||
p.ClearedDate.ToString("d").Contains(globalSearch.ToString()) ||
p.SentDate.ToString("d").Contains(globalSearch.ToString()));
或
ToShortDateString() 等价于小写的d ToString("d")
query = query.Where(p =>
p.ChckNumber.ToString().Contains(globalSearch.ToString()) ||
p.BankAccount.ToString().Contains(globalSearch.ToString()) ||
p.Description.ToString().Contains(globalSearch.ToString()) ||
p.CheckAmount.ToString().Contains(globalSearch) ||
p.ClearedDate.ToShortDateString().Contains(globalSearch.ToString()) ||
p.SentDate.ToShortDateString().Contains(globalSearch.ToString()));
尝试格式化你的日期部分
p.ClearedDate.ToString("dd/MM/yyyy").Contains(globalSearch.ToString("dd/MM/yyyy"))
也可以试试 linq Pad 或类似工具或任何 linq 辅助扩展,看看 SQL 会出现什么
你应该根据你的要求使用格式。由数字编码的所有日期时间格式。
For instance, 110 -> mm-dd-yyyy
SELECT CONVERT(VARCHAR(MAX), ClearedDate, 110) FROM myTable
您的代码将 return 行,其中查询中的第一个字段与查询词匹配。这是一个现实的要求吗?我建议不要。查询词必须针对已知的特定字段。
您真的有兴趣将查询词作为字段内容的子字符串吗?至少在整数和日期字段的情况下,这似乎不太可能,但由于您没有说明查询词可以包含的值,因此无法确定。
没有必要转换 varchar 字段 .ToString()
,因为它们已经是字符串。同样,如果您在查询 DateTime
或 Integer
字段时提供了适当类型的查询词,则您也不需要转换它们(假设您实际上不是在查询子字符串)。这将避免空字段值的问题,并将消除更多冗余处理。
考虑到这些要点,您可能需要重新设计查询。与其使用 "one size fits all" 查询对象,我建议您采取更慎重的方法。
例如,您可以为每个查询字段创建一个包含可为 null 的 属性 的查询对象。
public partial class AccountQuery
{
public string CheckNumber { get; set; }
public string BankAccount { get; set; }
public string Description { get; set; }
public int? CheckAmount { get; set; }
public DateTime? ClearedDate { get; set; }
public DateTime? SentDate { get; set; }
}
向您的实体模型/DTO 添加一个方法来封装查询逻辑。它接受一个 AccountQuery 对象并将其上的任何非空属性与相应的实体 属性 匹配。
public class Account
{
public string CheckNumber { get; set; }
public string BankAccount { get; set; }
public string Description { get; set; }
public int CheckAmount { get; set; }
public DateTime ClearedDate { get; set; }
public DateTime SentDate { get; set; }
public bool Matches(AccountQuery query)
{
return (!string.IsNullOrEmpty(query.CheckNumber) && query.CheckNumber == CheckNumber) ||
(!string.IsNullOrEmpty(query.BankAccount) && query.BankAccount == BankAccount) ||
(!string.IsNullOrEmpty(query.Description) && query.Description == Description) ||
(query.ClearedDate.HasValue && query.ClearedDate == ClearedDate) ||
(query.SentDate.HasValue && query.SentDate == SentDate) ||
(query.CheckAmount.HasValue && query.CheckAmount == CheckAmount);
}
}
您的查询将变成,例如:
var aq = new AccountQuery
{
ClearedDate = DateTime.Today
};
query.Where(p => p.Matches(aq));
请注意,此查询的逻辑与您的原始代码不同,正如我在上面指出的那样,这似乎不现实。
抱歉回答晚了
不要对数字使用 ToString
而是检查全局搜索字符串是否为 NUmeric,
如果它是数字,则将其转换为必填字段,如整数或双精度。
至于日期时间,
将日期格式化程序用作 p.ClearedDate.ToString("dd/MM/yyyy"),无需格式化全局搜索,因为它将采用给定格式
我的解决方案可能是这样,
查询=query.Where(p =>
p.ChckNumber==int.TryParse(globalSearch.ToString, out num)?num:globalSearch.ToString(); ||
p.BankAccount.ToString().包含(globalSearch.ToString()) ||
p.Description.ToString().包含(globalSearch.ToString()) ||
p.CheckAmount==decimal.TryParse(globalSearch.ToString, out num)?num:globalSearch.ToString(); ||
p.ClearedDate.ToString("dd/MM/yyyy").包含(globalSearch.ToString()) ||
p.SentDate.ToString("dd/MM/yyyy").包含(globalSearch.ToString()));
我正在处理这行代码:
query = query.Where(p =>
p.ChckNumber.ToString().Contains(globalSearch.ToString()) ||
p.BankAccount.ToString().Contains(globalSearch.ToString()) ||
p.Description.ToString().Contains(globalSearch.ToString()) ||
p.CheckAmount.ToString().Contains(globalSearch) ||
p.ClearedDate.ToString().Contains(globalSearch.ToString()) ||
p.SentDate.ToString().Contains(globalSearch.ToString()));
使用这行代码,我基本上是在进行搜索,当 globalSearch
是 string
并且像 BankAccount
和 Description
这样的列时,它似乎工作正常是 varchar
,但是,当 globalSearch
是 Int
或 DateTime
(-2233 或 4/9/2013)时,对于列 CheckAmount (int)
、ClearedDate (DateTime)
, SentDate (DateTime)
, 它 return 0 行,如果 globalSearch
匹配 ChckNumber
中的 int
它有效!
我做错了什么?
我运行这个查询在SQL服务器:
SELECT CONVERT(VARCHAR(MAX), ClearedDate) FROM myTable
和我所有的日期 return 2017 年 9 月 9 日 如果 globalSearch
是 2017 年 9 月 10 日,它可以工作,但它不适用于我需要的格式:9/9/2017
您不应该关心 globalSearch 是否是 Int,因为您应该始终将它转换为字符串,除非是 DateTime,并且您不应该关心列是 varchar 还是 Int,因为您总是将列转换为字符串,除非 DateTime.
注意,根据您的评论,我假设您只比较月、日和年,并不关心 ClearedDate 的时间
我发现您的代码存在三个潜在问题:
- 您没有将 globalSearch 转换为 CheckAmount 列的字符串
- 您在调用 .ToString 之前没有检查任何列的空值,也许您的所有列都不允许空值
- 您的代码可读性不是很好,人眼很难发现不一致之处。
这里是每次都将 globalSearch 转换为字符串的更具可读性的代码,因为同样,您不会将 globalSearch 转换为 CheckAmount 的字符串:
var gsStr = globalSearch.ToString();
var gsDate = DateTime.MinDate;
if(globalSearch.GetType() == typeof(DateTime))
{
gsDate = globalSearch;
}
query = query.Where(p => p.ChckNumber.ToString().Contains(gsStr)
|| p.BankAccount.ToString().Contains(gsStr)
|| p.Description.ToString().Contains(gsStr)
|| p.CheckAmount.ToString().Contains(gsStr)
|| p.ClearedDate.Date == gsDate.Date
|| p.SentDate.ToString().Contains(gsStr));
如果您使用的是 C# 6.0,则可以使用新的 Null Propagation Operator 来防止错误,如果您的任何列现在或将来确实允许 null:
var gsStr = globalSearch.ToString();
var gsDate = DateTime.MinDate;
if(globalSearch.GetType() == typeof(DateTime))
{
gsDate = globalSearch;
}
query = query.Where(p => p.ChckNumber?.ToString().Contains(gsStr)
|| p.BankAccount?.ToString().Contains(gsStr)
|| p.Description?.ToString().Contains(gsStr)
|| p.CheckAmount?.ToString().Contains(gsStr)
|| p.ClearedDate?.Date == gsDate.Date
|| p.SentDate?.ToString().Contains(gsStr));
将 globalSearch ToString 转换为 CheckAmount Contains 可能会解决您的问题,使您的代码更具可读性并防止出现空值,如果它没有修复错误,则更容易调试。
您好,如果您正在寻找日期的正确格式,请试试这个。
SELECT CONVERT(VARCHAR(10), SYSDATETIME(), 103)
单字符日期格式。我们可以使用 char 作为 ToString 的参数来指定预设格式。这些是标准格式。
query = query.Where(p =>
p.ChckNumber.ToString().Contains(globalSearch.ToString()) ||
p.BankAccount.ToString().Contains(globalSearch.ToString()) ||
p.Description.ToString().Contains(globalSearch.ToString()) ||
p.CheckAmount.ToString().Contains(globalSearch) ||
p.ClearedDate.ToString("d").Contains(globalSearch.ToString()) ||
p.SentDate.ToString("d").Contains(globalSearch.ToString()));
或
ToShortDateString() 等价于小写的d ToString("d")
query = query.Where(p =>
p.ChckNumber.ToString().Contains(globalSearch.ToString()) ||
p.BankAccount.ToString().Contains(globalSearch.ToString()) ||
p.Description.ToString().Contains(globalSearch.ToString()) ||
p.CheckAmount.ToString().Contains(globalSearch) ||
p.ClearedDate.ToShortDateString().Contains(globalSearch.ToString()) ||
p.SentDate.ToShortDateString().Contains(globalSearch.ToString()));
尝试格式化你的日期部分
p.ClearedDate.ToString("dd/MM/yyyy").Contains(globalSearch.ToString("dd/MM/yyyy"))
也可以试试 linq Pad 或类似工具或任何 linq 辅助扩展,看看 SQL 会出现什么
你应该根据你的要求使用格式。由数字编码的所有日期时间格式。
For instance, 110 -> mm-dd-yyyy
SELECT CONVERT(VARCHAR(MAX), ClearedDate, 110) FROM myTable
您的代码将 return 行,其中查询中的第一个字段与查询词匹配。这是一个现实的要求吗?我建议不要。查询词必须针对已知的特定字段。
您真的有兴趣将查询词作为字段内容的子字符串吗?至少在整数和日期字段的情况下,这似乎不太可能,但由于您没有说明查询词可以包含的值,因此无法确定。
没有必要转换 varchar 字段 .ToString()
,因为它们已经是字符串。同样,如果您在查询 DateTime
或 Integer
字段时提供了适当类型的查询词,则您也不需要转换它们(假设您实际上不是在查询子字符串)。这将避免空字段值的问题,并将消除更多冗余处理。
考虑到这些要点,您可能需要重新设计查询。与其使用 "one size fits all" 查询对象,我建议您采取更慎重的方法。
例如,您可以为每个查询字段创建一个包含可为 null 的 属性 的查询对象。
public partial class AccountQuery
{
public string CheckNumber { get; set; }
public string BankAccount { get; set; }
public string Description { get; set; }
public int? CheckAmount { get; set; }
public DateTime? ClearedDate { get; set; }
public DateTime? SentDate { get; set; }
}
向您的实体模型/DTO 添加一个方法来封装查询逻辑。它接受一个 AccountQuery 对象并将其上的任何非空属性与相应的实体 属性 匹配。
public class Account
{
public string CheckNumber { get; set; }
public string BankAccount { get; set; }
public string Description { get; set; }
public int CheckAmount { get; set; }
public DateTime ClearedDate { get; set; }
public DateTime SentDate { get; set; }
public bool Matches(AccountQuery query)
{
return (!string.IsNullOrEmpty(query.CheckNumber) && query.CheckNumber == CheckNumber) ||
(!string.IsNullOrEmpty(query.BankAccount) && query.BankAccount == BankAccount) ||
(!string.IsNullOrEmpty(query.Description) && query.Description == Description) ||
(query.ClearedDate.HasValue && query.ClearedDate == ClearedDate) ||
(query.SentDate.HasValue && query.SentDate == SentDate) ||
(query.CheckAmount.HasValue && query.CheckAmount == CheckAmount);
}
}
您的查询将变成,例如:
var aq = new AccountQuery
{
ClearedDate = DateTime.Today
};
query.Where(p => p.Matches(aq));
请注意,此查询的逻辑与您的原始代码不同,正如我在上面指出的那样,这似乎不现实。
抱歉回答晚了
不要对数字使用 ToString
而是检查全局搜索字符串是否为 NUmeric,
如果它是数字,则将其转换为必填字段,如整数或双精度。 至于日期时间,
将日期格式化程序用作 p.ClearedDate.ToString("dd/MM/yyyy"),无需格式化全局搜索,因为它将采用给定格式
我的解决方案可能是这样,
查询=query.Where(p => p.ChckNumber==int.TryParse(globalSearch.ToString, out num)?num:globalSearch.ToString(); || p.BankAccount.ToString().包含(globalSearch.ToString()) || p.Description.ToString().包含(globalSearch.ToString()) || p.CheckAmount==decimal.TryParse(globalSearch.ToString, out num)?num:globalSearch.ToString(); || p.ClearedDate.ToString("dd/MM/yyyy").包含(globalSearch.ToString()) || p.SentDate.ToString("dd/MM/yyyy").包含(globalSearch.ToString()));