1 mysql asp.net-mvc entity-framework entity-framework-6 entity-framework-migrations
我使用实体框架 6 和 msyql 数据库创建了一个新的 .NET MVC 5 Web 应用程序。我首先使用代码/模型。数据库服务器有一个默认的存储引擎 MyISAM,但我希望 EF 创建的表是 InnoDb。有谁知道是否有办法指定 EF 将在CREATE TABLE语句中使用的存储引擎?
实际上,MySQL EF 提供程序使用的引擎始终是 InnoDB,如果不重写 DDL 生成器,就无法更改它。
要尝试,您可以创建一个简单的项目并启用 MySQL 登录。你会注意到每个 create 语句都会以engine=InnoDb auto_increment=0
例如这个类
public class Blog
{
public int BlogId { get; set; }
[MaxLength(200)]
public string Name { get; set; }
[MaxLength(200)]
public string Topic { get; set; }
public DateTime LastUpdated { get; set; }
[DefaultValue(0)]
public int Order { get; set; }
public virtual List<Post> Posts { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
使用标准 MySQL EF 提供程序迁移,生成此 MySQL DDL 语句
CREATE TABLE `Blogs` (
`BlogId` INT NOT NULL auto_increment,
`Name` NVARCHAR(200),
`Topic` NVARCHAR(200),
`LastUpdated` DATETIME NOT NULL,
`Order` INT NOT NULL,
PRIMARY KEY (`BlogId`)
) engine = InnoDb auto_increment = 0
Run Code Online (Sandbox Code Playgroud)
engine = InnoDb来自哪里?它在迁移源代码中进行了硬编码。
您可以查看迁移源代码
https://github.com/mysql/mysql-connector-net/blob/6.9/Source/MySql.Data.EntityFramework5/MySqlMigrationSqlGenerator.cs
方法MySqlMigrationSqlGenerator.Generate(CreateTableOperation op)。最后一句话是sb.Append(") engine=InnoDb auto_increment=0");
因此,正确的问题应该是如何将引擎从 InnoDB 更改为另一个引擎。您可以继承 MySqlMigrationSqlGenerator 类并覆盖该方法,即:
internal class MyOwnMigrationSqlGenerator : MySqlMigrationSqlGenerator
{
public MyOwnMigrationSqlGenerator()
{
Engine = "InnoDB";
}
public MyOwnMigrationSqlGenerator(string engine)
{
Engine = engine;
}
private readonly List<MigrationStatement> _specialStatements = new List<MigrationStatement>();
public string Engine { get; set; }
public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
{
List<MigrationStatement> migrationStatements = base.Generate(migrationOperations, providerManifestToken).ToList();
migrationStatements.AddRange(_specialStatements);
return migrationStatements;
}
protected override MigrationStatement Generate(CreateTableOperation op)
{
StringBuilder sb = new StringBuilder();
string tableName = TrimSchemaPrefix(op.Name);
var autoIncrementCols = (List<string>)(typeof(MySqlMigrationSqlGenerator).GetProperty("autoIncrementCols", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this));
var primaryKeyCols = (List<string>)(typeof(MySqlMigrationSqlGenerator).GetProperty("primaryKeyCols", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this));
sb.Append("create table " + "`" + tableName + "`" + " (");
if (op.PrimaryKey != null)
{
op.PrimaryKey.Columns.ToList().ForEach(col => primaryKeyCols.Add(col));
}
//columns
sb.Append(string.Join(",", op.Columns.Select(c => "`" + c.Name + "` " + Generate(c))));
// Determine columns that are GUID & identity
List<ColumnModel> guidCols = new List<ColumnModel>();
ColumnModel guidPk = null;
foreach (ColumnModel columnModel in op.Columns)
{
if (columnModel.Type == PrimitiveTypeKind.Guid && columnModel.IsIdentity && String.Compare(columnModel.StoreType, "CHAR(36) BINARY", true) == 0)
{
if (primaryKeyCols.Contains(columnModel.Name))
guidPk = columnModel;
guidCols.Add(columnModel);
}
}
if (guidCols.Count != 0)
{
var createTrigger = new StringBuilder();
createTrigger.AppendLine(string.Format("DROP TRIGGER IF EXISTS `{0}_IdentityTgr`;", TrimSchemaPrefix(tableName)));
createTrigger.AppendLine(string.Format("CREATE TRIGGER `{0}_IdentityTgr` BEFORE INSERT ON `{0}`", TrimSchemaPrefix(tableName)));
createTrigger.AppendLine("FOR EACH ROW BEGIN");
foreach (ColumnModel opCol in guidCols)
createTrigger.AppendLine(string.Format("SET NEW.{0} = UUID();", opCol.Name));
createTrigger.AppendLine(string.Format("DROP TEMPORARY TABLE IF EXISTS tmpIdentity_{0};", TrimSchemaPrefix(tableName)));
createTrigger.AppendLine(string.Format("CREATE TEMPORARY TABLE tmpIdentity_{0} (guid CHAR(36))ENGINE=MEMORY;", TrimSchemaPrefix(tableName)));
createTrigger.AppendLine(string.Format("INSERT INTO tmpIdentity_{0} VALUES(New.{1});", TrimSchemaPrefix(tableName), guidPk.Name));
createTrigger.AppendLine("END");
var sqlOp = new SqlOperation(createTrigger.ToString());
_specialStatements.Add(Generate(sqlOp));
}
if (op.PrimaryKey != null) // && !sb.ToString().Contains("primary key"))
{
sb.Append(",");
sb.Append("primary key ( " + string.Join(",", op.PrimaryKey.Columns.Select(c => "`" + c + "`")) + ") ");
}
string keyFields = ",";
autoIncrementCols.ForEach(col => keyFields += (!primaryKeyCols.Contains(col) ? string.Format(" KEY (`{0}`),", col) : ""));
sb.Append(keyFields.Substring(0, keyFields.LastIndexOf(",")));
sb.Append(string.Format(") engine={0} auto_increment=0", Engine));
return new MigrationStatement() { Sql = sb.ToString() };
}
private string TrimSchemaPrefix(string table)
{
if (table.StartsWith("dbo.") || table.Contains("dbo."))
return table.Replace("dbo.", "");
return table;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,在您的迁移配置中,您可以指定自己的 sql 生成器。
internal sealed class MyContextMigrationConfiguration : DbMigrationsConfiguration<MyContext>
{
public MyContextMigrationConfiguration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
SetSqlGenerator("MySql.Data.MySqlClient", new MyOwnMigrationSqlGenerator("MyPreferredEngine"));
}
}
Run Code Online (Sandbox Code Playgroud)
编辑
MyOwnMigrationSqlGenerator 类有一个错误。可能最好的办法是重写所有 MySqlMigrationSqlGenerator。在这种情况下,我只是修复了访问 MySqlMigrationSqlGenerator 私有字段的类(这很糟糕)。
| 归档时间: |
|
| 查看次数: |
1279 次 |
| 最近记录: |