可查询的WHERE包含String,Int,DateTime

时间:2017-03-02 16:53:59

标签: c# sql iqueryable

我正在使用这行代码:

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()));

使用这行代码我基本上都在进行搜索,当globalSearchstring并且BankAccountDescription之类的列为{时,它似乎正常工作{1}},varchar globalSearchInt( - 2233或4/9/2013)列为DateTimeCheckAmount (int)时{1}} ,ClearedDate (DateTime),它会返回0行,如果SentDate (DateTime)globalSearch 中的int匹配,则可以正常工作!

我做错了什么?

我在SQL Server中运行了这个查询:

ChckNumber

我的所有日​​期都将于2017年9月9日返回如果SELECT CONVERT(VARCHAR(MAX), ClearedDate) FROM myTable是2017年9月10日,则可以使用,但它不适用于我需要的格式:9/9/2017

7 个答案:

答案 0 :(得分:7)

你不应该关心globalSearch是否是一个Int因为你应该总是将它转换为一个字符串,除非是DateTime而你不应该关心一个列是一个varchar还是一个Int,因为你总是将列转换为字符串,除非DateTime

请注意,我根据您的评论做出假设,即您只是比较月,日和年,而不关心ClearedDate的时间

我发现您的代码存在三个潜在问题:

  1. 您不会将globalSearch转换为列CheckAmount
  2. 的字符串
  3. 在调用.ToString之前,您不会检查任何列的空值,也许您的所有列都不允许空值
  4. 你的代码不易读,人眼很难发现不一致。
  5. 以下是更易读的代码,它将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来防止错误,如果您的任何列现在或将来都允许空值:

    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));
    

    为CheckAmount转换globalSearch ToString包含可以解决您的问题,使您的代码更具可读性并防止空值,如果它不能修复bug,将使调试变得更容易。

答案 1 :(得分:2)

您的代码将返回查询中第一个字段与查询字词匹配的行。这是一个现实的要求吗?我建议不要。查询术语必须指向已知的特定字段。

您是否真的有兴趣将查询字词作为字段内容的子字符串?至少在整数和日期字段的情况下,这似乎不太可能,但是由于您没有说明您的查询字词可以包含的值,因此无法确定。

没有必要转换varchar字段.ToString(),因为它们已经是字符串。同样,如果您在查询DateTimeInteger字段时提供了相应类型的查询字词,则您也不需要转换它们(假设您实际上并未查询子字符串) 。这将避免使用空字段值的问题,并将删除更多的冗余处理。

您可能需要在考虑这些要点的情况下重新设计查询。而不是使用"一个尺寸适合所有"查询对象,我建议你采取更深思熟虑的方法。

例如,您可以创建一个查询对象,其中包含每个查询字段的可空属性。

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对象,并将其上的任何非null属性与相应的实体属性进行匹配。

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));

请注意,此查询的逻辑与原始代码不同,正如我上面所指出的,这似乎不太现实。

答案 2 :(得分:2)

对于迟到的答案感到抱歉

不要使用ToString for Numerics

而是检查globalsearch字符串是否为NUmeric,

如果是数字,则将其转换为必需字段,如整数或双精度。 至于相关的DateTime,

使用Date格式化程序作为p.ClearedDate.ToString(" dd / MM / yyyy")并且不需要格式化globalsearch,因为它将采用给定的格式

我的解决方案可能是这个,

query = 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&#34)。包含(globalSearch.ToString()));

答案 3 :(得分:1)

如果您正在寻找正确的日期格式,请试试这个。

SELECT CONVERT(VARCHAR(10), SYSDATETIME(), 103)

答案 4 :(得分:1)

单一日期格式。我们可以使用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()));

OR

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()));

答案 5 :(得分:1)

尝试设置日期部分的格式

 p.ClearedDate.ToString("dd/MM/yyyy").Contains(globalSearch.ToString("dd/MM/yyyy"))

还可以尝试使用linq Pad或类似工具或任何linq帮助扩展来查看SQL出现的内容

答案 6 :(得分:1)

您应该根据您的要求使用格式。全部日期时间格式由数字编码。

  

例如,110 - > MM-DD-YYYY

 SELECT CONVERT(VARCHAR(MAX), ClearedDate, 110) FROM myTable