LINQ to Entities区分大小写比较

时间:2010-10-01 21:07:38

标签: c# .net entity-framework-4 linq-to-entities

这不是LINQ to Entities中的区分大小写的比较:

Thingies.First(t => t.Name == "ThingamaBob");

如何与LINQ to Entities实现区分大小写的比较?

8 个答案:

答案 0 :(得分:150)

那是因为您正在使用 LINQ To Entities ,它最终将您的Lambda表达式转换为SQL语句。这意味着区分大小写受SQL Server的支配,默认情况下 SQL_Latin1_General_CP1_CI_AS 整理并且不区分大小写。

使用 ObjectQuery.ToTraceString 查看实际提交给SQL Server的生成的SQL查询揭示了这个谜团:

string sqlQuery = ((ObjectQuery)context.Thingies
        .Where(t => t.Name == "ThingamaBob")).ToTraceString();

当您创建 LINQ to Entities 查询时, LINQ to Entities 利用LINQ解析器开始处理查询并将其转换为LINQ表达式树。然后将LINQ表达式树传递给 Object Services API,后者将表达式树转换为命令树。然后将其发送到商店提供商(例如SqlClient),后者将命令树转换为本机数据库命令文本。查询在数据存储上执行,结果由对象服务 实体化实体对象中。在考虑区分大小写之间没有任何逻辑。因此,无论您在谓词中添加什么案例,除非您更改该列的SQL Server Collat​​es,否则SQL Server将始终视为相同。

服务器端解决方案:

因此,最佳解决方案是将 Thingies 表中 Name 列的排序规则更改为COLLATE Latin1_General_CS_AS < / strong>在SQL Server上运行它是区分大小写的:

ALTER TABLE Thingies
ALTER COLUMN Name VARCHAR(25)
COLLATE Latin1_General_CS_AS

有关 SQL Server Collat​​es 的详细信息,请查看SQL SERVER Collate Case Sensitive SQL Query Search

客户端解决方案:

您可以在客户端应用的唯一解决方案是使用 LINQ to Objects 进行另一个看似不太优雅的比较:

Thingies.Where(t => t.Name == "ThingamaBob")
        .AsEnumerable()
        .First(t => t.Name == "ThingamaBob");

答案 1 :(得分:10)

您可以为EF6 + Code-first

添加[CaseSensitive]注释

添加此类

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class CaseSensitiveAttribute : Attribute
{
    public CaseSensitiveAttribute()
    {
        IsEnabled = true;
    }
    public bool IsEnabled { get; set; }
}

public class CustomSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
    protected override void Generate(AlterColumnOperation alterColumnOperation)
    {
        base.Generate(alterColumnOperation);
        AnnotationValues values;
        if (alterColumnOperation.Column.Annotations.TryGetValue("CaseSensitive", out values))
        {
            if (values.NewValue != null && values.NewValue.ToString() == "True")
            {
                using (var writer = Writer())
                {
                    //if (System.Diagnostics.Debugger.IsAttached == false) System.Diagnostics.Debugger.Launch();

                    // https://github.com/mono/entityframework/blob/master/src/EntityFramework.SqlServer/SqlServerMigrationSqlGenerator.cs
                    var columnSQL = BuildColumnType(alterColumnOperation.Column); //[nvarchar](100)
                    writer.WriteLine(
                        "ALTER TABLE {0} ALTER COLUMN {1} {2} COLLATE SQL_Latin1_General_CP1_CS_AS {3}",
                        alterColumnOperation.Table,
                        alterColumnOperation.Column.Name,
                        columnSQL,
                        alterColumnOperation.Column.IsNullable.HasValue == false || alterColumnOperation.Column.IsNullable.Value == true ? " NULL" : "NOT NULL" //todo not tested for DefaultValue
                        );
                    Statement(writer);
                }
            }
        }
    }
}

public class CustomApplicationDbConfiguration : DbConfiguration
{
    public CustomApplicationDbConfiguration()
    {
        SetMigrationSqlGenerator(
            SqlProviderServices.ProviderInvariantName,
            () => new CustomSqlServerMigrationSqlGenerator());
    }
}

修改您的DbContext,添加

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention<CaseSensitiveAttribute, bool>(
                "CaseSensitive",
                (property, attributes) => attributes.Single().IsEnabled));
        base.OnModelCreating(modelBuilder);
    }

然后做

添加迁移CaseSensitive

更新的数据库的

基于文章https://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/并修复了一些错误

答案 2 :(得分:9)

默认情况下,SQL Server中的

WHERE条件不区分大小写。通过将列的默认排序规则(SQL_Latin1_General_CP1_CI_AS)更改为SQL_Latin1_General_CP1_CS_AS,使其区分大小写。

执行此操作的脆弱方法是使用代码。添加新的迁移文件,然后在Up方法中添加:

public override void Up()
{
   Sql("ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL");
}

<强>但是

您可以创建名为&#34; CaseSensitive&#34;的自定义注释。使用新的EF6功能,你可以像这样装饰你的属性:

[CaseSensitive]
public string Name { get; set; }

blog post解释了如何做到这一点。

答案 3 :(得分:1)

@Morteza Manavi给出的答案解决了这个问题。仍然,为 客户端解决方案,优雅的方式如下(添加双重检查)。

var firstCheck = Thingies.Where(t => t.Name == "ThingamaBob")
    .FirstOrDefault();
var doubleCheck = (firstCheck?.Name == model.Name) ? Thingies : null;

答案 4 :(得分:-4)

我喜欢Morteza的回答,并且通常更喜欢修复服务器端。 对于客户端我通常使用:

Dim bLogin As Boolean = False

    Dim oUser As User = (From c In db.Users Where c.Username = UserName AndAlso c.Password = Password Select c).SingleOrDefault()
    If oUser IsNot Nothing Then
        If oUser.Password = Password Then
            bLogin = True
        End If
    End If

基本上,首先检查是否有符合要求标准的用户,然后检查密码是否相同。 有点啰嗦,但我觉得当涉及到一大堆标准时,它更容易阅读。

答案 5 :(得分:-4)

StringComparison.IgnoreCase都没有为我工作。但这样做了:

context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper()));

答案 6 :(得分:-5)

使用string.Equals

Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture);

此外,您不必担心null并只返回您想要的信息。

对Case Case不敏感使用StringComparision.CurrentCultureIgnoreCase。

Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase);

答案 7 :(得分:-6)

不确定EF4,但EF5支持:

Thingies
    .First(t => t.Name.Equals(
        "ThingamaBob",
        System.StringComparison.InvariantCultureIgnoreCase)