【问题标题】:Relax C# LINQ String Comparison (Trim, Case Insensitive, ??)放松 C# LINQ 字符串比较(修剪、不区分大小写、??)
【发布时间】:2016-02-28 01:14:09
【问题描述】:

问题

背景故事:我正在将遗留系统的所有 SQL 查询重写为 LINQ。

数据库没有我预期的那么干净。由于这些 SQL 记录中有许多包含空格或不同的情况,因此视为相同。

SELECT * 
FROM fruit 
WHERE name = @fruitname;

如果@fruitname 是apple,此查询将匹配以apple、_apple、APPLE_ 结尾的任何记录(其中_ 是一个空白字符)。

但是,这是我的用例中的预期行为。

另一方面,LINQ 字符串比较更精确。这让我很恼火,因为这些问题不断浮现在我的脑海中。

设置

FruitTableAdapter fruitsAdapter = new FruitTableAdapter();
MyGardenDataSet.FruitDataTable fruitsTable = fruitsAdapter.GetData();

方法

// Issue 1: Does not match, '_apple' or 'APPLE_'
var fruits1 = fruitsTable.Where(row=>row.name == fruitname);

// Issue 2: String Comparison with case insensitive (does not match 'APPLE')
var fruits2 = fruitsTable.Where(
    row=>row.nameEquals(fruitname, StringComparison.OrdinalIgnoreCase));

// Issue 3: Trailing space with case insensitive
var fruits2 = fruitsTable.Where(
    row=>row.name.Trim().Equals(fruitname.Trim(), 
                                StringComparison.OrdinalIgnoreCase));

我不确定,但 SQL 查询与字符串比较可能存在很多问题。

是否有任何 SQL 感知 StringComparison?如何在 LINQ 中实现与 SQL 相同的字符串比较?

【问题讨论】:

  • linq 不区分大小写(没有 toUpper 或 toLower)stackoverflow.com/questions/5312585/…
  • 是的,我见过很多这样的方法,但它们都没有结合CaseInsensitive 和Trim。但我还没有看到两者的结合。或者也许除了 2 之外还有更多不同
  • 如果您使用 LINQ to 实体,您的比较 should already work as you want,因为您的 LINQ 表达式被转换为 SQL,因此使用 SQL 比较。如果您使用 LINQ 来反对,这将是开始担心性能的好时机......
  • @Heinzi 感谢您的链接。我相信现在的问题可能是这个fruitsTable 不再是SQL,而是已经变成了Object。这导致== 的比较无法相应地工作。我现在正在调查这个问题。
  • 欢迎来到 Linq,@Yeo :-)

标签: c# string linq


【解决方案1】:

这是一个很晚的答案。

您可以使用Regex 来解决您的问题 这是我尝试过的,希望对你有帮助

我创建了一个示例类

 public class SampleTable
 {
     public string Name { get; set; }

     public SampleTable(string name)
     {
        Name = name;
     }
 }

填充的样本数据

List<SampleTable> sampleTblList = new List<SampleTable>();
sampleTblList.Add(new SampleTable(" Apple"));
sampleTblList.Add(new SampleTable(" APPLE"));
sampleTblList.Add(new SampleTable("Apple"));
sampleTblList.Add(new SampleTable("apple"));
sampleTblList.Add(new SampleTable("apple "));
sampleTblList.Add(new SampleTable("apmangple"));

解决方案:-

string fruitName = "apple";
List<SampleTable> sortedSampleTblList = sampleTblList.Where(x => 
Regex.IsMatch(fruitName, x.Name, RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase)).ToList();

输出:-

string ans = String.Join(",", sortedSampleTblList.Select(x => x.Name.Replace(" ","_")).ToArray());
Console.Write(ans);

_Apple,_APPLE,Apple,apple,apple_

【讨论】:

  • 是的,但这不应该在内存中完成。应该告诉 OP 使用将 LINQ 语句转换为 SQL 的 OR-mapper。通常 SQL 是不区分大小写的,它会修剪字符串值。
  • @GertArnold 正如你所说,我的回答不值得 OP
【解决方案2】:

fruitsTable.Where(row =&gt; row.name.Trim().Equals(fruitname, StringComparison.OrdinalIgnoreCase)); 应该做你需要的,但我很困惑,因为你在问题 3 下列出了几乎相同的内容。你是否没有意识到它正在工作,因为你正在重复使用 fruits2?

这个小 NUnit 测试通过了

[Test]
public void FruitTest()
{
    var fruitsTable = new List<string> { " Apple", " APPLE", "Apple", "apple", "apple ", " apple", "APPLE " };
    var fruitname = "apple ".Trim();

    var fruits = fruitsTable.Where(row => row.Trim().Equals(fruitname, StringComparison.OrdinalIgnoreCase));

    Assert.AreEqual(fruitsTable.Count(), fruits.Count());
}

【讨论】:

    【解决方案3】:

    这是一个很好的字符串扩展方法,它建立在关于套管StackOverflow 的类似问题的解决方案之上

    请记住,我们希望在修剪场景中允许 NULL 字符串,因此此扩展将在检查空值后对修剪后的字符串进行不区分大小写的比较

    public static class StringExtension
    {
        // Trim strings and compare values without casing
        public static bool SqlCompare(this string source, string value)
        {
            // Handle nulls before trimming
            if (!string.IsNullOrEmpty(source))
                source = source.Trim();
    
            if (!string.IsNullOrEmpty(value))
                value = value.Trim();
    
            // Compare strings (case insensitive)
            return string.Equals(source, value, StringComparison.CurrentCultureIgnoreCase);
        }
    }
    

    以下是如何在 LINQ 语句中使用扩展:

    (SysUserDisplayFavorites 表由带有空格填充结果的 char() 字段组成。这些字段将被修剪并与 displayFavorite 对象中用户提供的值进行比较(不区分大小写)

                        var defaultFavorite = _context.SysUserDisplayFavorites
                        .Where(x => x.UserId.SqlCompare(displayFavorite.UserId))
                        .Where(x => x.ModuleCode.SqlCompare(displayFavorite.ModuleCode))
                        .Where(x => x.ActivityCode.SqlCompare(displayFavorite.ActivityCode))
                        .Where(x => x.ActivityItemCode.SqlCompare(displayFavorite.ActivityItemCode))
                        .Where(x => x.IsDefault);
    

    【讨论】:

    • 这应该在内存中工作......而不是直接到 SQL,不是吗?
    猜你喜欢
    • 2021-05-09
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    • 2014-06-20
    • 2013-06-29
    • 1970-01-01
    相关资源
    最近更新 更多