App*_*ere 18 sql-server ef-code-first entity-framework-4.1
我想在Entity Framework Code First创建数据库时设置数据库的默认排序规则.
我尝试过以下方法:
public class TestInitializer<T> : DropCreateDatabaseAlways<T> where T: DbContext
{
protected override void Seed(T context)
{
context.Database.ExecuteSqlCommand("ALTER DATABASE [Test] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
context.Database.ExecuteSqlCommand("ALTER DATABASE [Test] COLLATE Latin1_General_CI_AS");
context.Database.ExecuteSqlCommand("ALTER DATABASE [Test] SET MULTI_USER");
}
}
Run Code Online (Sandbox Code Playgroud)
当SQL Server 已设置为相同的默认排序规则Latin1_General_CI_AS 时,这似乎运行正常.
但是如果我指定了不同的排序规则,比如说SQL_Latin1_General_CP1_CI_AS 则会因错误而失败,
System.Data.SqlClient.SqlException: Resetting the connection results in a different
state than the initial login. The login fails.
Run Code Online (Sandbox Code Playgroud)
任何人都可以建议我如何设置校对吗?
这绝对是可能的,虽然它有点像黑客.您可以使用命令拦截器更改CREATE DATABASE命令.Il将拦截发送到数据库的所有命令,根据正则表达式识别数据库创建命令,并使用排序规则更改命令文本.
DbInterception.Add(new CreateDatabaseCollationInterceptor("SQL_Romanian_Cp1250_CI_AS_KI_WI"));
Run Code Online (Sandbox Code Playgroud)
public class CreateDatabaseCollationInterceptor : IDbCommandInterceptor
{
private readonly string _collation;
public CreateDatabaseCollationInterceptor(string collation)
{
_collation = collation;
}
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { }
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
// Works for SQL Server
if (Regex.IsMatch(command.CommandText, @"^create database \[.*]$"))
{
command.CommandText += " COLLATE " + _collation;
}
}
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { }
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { }
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { }
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { }
}
Run Code Online (Sandbox Code Playgroud)
由于数据库是从一开始就使用正确的排序规则创建的,因此所有列都将自动继承该排序规则,之后您不必更改它们.
请注意,它将影响在应用程序域内发生的任何后续数据库创建.因此,您可能希望在创建数据库后删除拦截器.
我能够通过自定义迁移 (EF6) 更改排序规则。我启用了自动迁移。您需要先删除您的数据库。
Add-Migration [YourCustomMigration]在包管理器控制台中键入来创建迁移代码。(代码优先迁移)ALTER DATABASE在表创建代码之前添加您的代码,以便使用您想要的数据库排序规则创建它们。另外,请注意suppressTransaction标志:
public override void Up()
{
Sql("ALTER DATABASE [YourDB] COLLATE [YourCollation]", suppressTransaction: true);
[...Your DB Objects Creation codes here...]
}
update-database从那时起发出的每个命令都会创建一个新的迁移类。所有迁移代码都按顺序执行。
我使用EFCore 的解决方案是从 SqlServerMigrationsSqlGenerator 派生并覆盖 Generate(SqlServerCreateDatabaseOperation, IModel, MigrationCommandListBuilder)
internal class CustomSqlServerMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator
{
internal const string DatabaseCollationName = "SQL_Latin1_General_CP1_CI_AI";
public CustomSqlServerMigrationsSqlGenerator(
MigrationsSqlGeneratorDependencies dependencies,
IMigrationsAnnotationProvider migrationsAnnotations)
: base(dependencies, migrationsAnnotations)
{
}
protected override void Generate(
SqlServerCreateDatabaseOperation operation,
IModel model,
MigrationCommandListBuilder builder)
{
base.Generate(operation, model, builder);
if (DatabaseCollationName != null)
{
builder
.Append("ALTER DATABASE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name))
.Append(" COLLATE ")
.Append(DatabaseCollationName)
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator)
.EndCommand(suppressTransaction: true);
}
}
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.ReplaceService<IMigrationsSqlGenerator, CustomSqlServerMigrationsSqlGenerator>();
}
Run Code Online (Sandbox Code Playgroud)
然后通过替换 IMigrationsSqlGenerator 服务在 DbContext 中使用它
public class MyDbContext : DbContext
{
//...
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.ReplaceService<IMigrationsSqlGenerator, CustomSqlServerMigrationsSqlGenerator>();
}
//...
}
Run Code Online (Sandbox Code Playgroud)
小智 5
不久前我遇到了同样的问题。可能的解决方案:
Seed()方法中更改数据库排序规则,但可以更改表的各个列的排序规则(注意:没有诸如表排序规则之类的东西,它确实与表中的列有关)。您必须分别更改每列的排序规则。Up()方法中更改表列排序规则。当您使用该Seed()方法时,我建议在该方法中进行以下操作(酌情修改)Seed():
context.Database.ExecuteSqlCommand(
@"ALTER TABLE MyTable ALTER COLUMN MyColumn NVARCHAR(max) COLLATE MyCollation NOT NULL");
Run Code Online (Sandbox Code Playgroud)
希望有帮助。