生成的标识符过长,无法用作约束名

11

我刚开始使用Entity Framework(4.3.1),并正在使用MySQL EF提供程序(6.5.4)创建一个使用TPT继承的代码优先模型。 当尝试创建数据库结构时,我收到了一个MySQLException "Identifier name 'LongClassNameOne_TypeConstraint_From_ClassName2s_To_LongClassNameOnes' is too long"错误消息(这是将派生类表格与父类表格关联的关系)。

   at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
   at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int32& insertedId)
   at MySql.Data.MySqlClient.Driver.GetResult(Int32 statementId, Int32& affectedRows, Int32& insertedId)
   at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
   at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
   at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
   at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader()
   at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery()
   at MySql.Data.MySqlClient.MySqlScript.Execute()
   at MySql.Data.MySqlClient.MySqlProviderServices.DbCreateDatabase(DbConnection connection, Nullable`1 commandTimeout, StoreItemCollection storeItemCollection)
   at System.Data.Objects.ObjectContext.CreateDatabase()
   at System.Data.Entity.Internal.DatabaseOperations.Create(ObjectContext objectContext)
   at System.Data.Entity.Internal.DatabaseCreator.CreateDatabase(InternalContext internalContext, Func`3 createMigrator, ObjectContext objectContext)
   at System.Data.Entity.Internal.InternalContext.CreateDatabase(ObjectContext objectContext)
   at System.Data.Entity.Database.Create()
   at System.Data.Entity.DropCreateDatabaseAlways`1.InitializeDatabase(TContext context)
   at System.Data.Entity.Database.<>c__DisplayClass2`1.<SetInitializerInternal>b__0(DbContext c)
   at System.Data.Entity.Internal.InternalContext.<>c__DisplayClass8.<PerformDatabaseInitialization>b__6()
   at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
   at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()
   at System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext c)
   at System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input)
   at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action)
   at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase()
   at System.Data.Entity.Internal.InternalContext.Initialize()
   at System.Data.Entity.Internal.InternalContext.ForceOSpaceLoadingForKnownEntityTypes()
   at System.Data.Entity.DbContext.System.Data.Entity.Infrastructure.IObjectContextAdapter.get_ObjectContext()
   ...

我该如何控制这个名称以使其更短,或者强制将其修剪为64个字符的名称限制,或者类似这样的操作?


恶魔问题。我无法回答这个问题,但对于SQL Server,我从未见过控制和自定义约束名称的方法。我甚至不确定是Entity Framework本身还是MySQL提供程序负责并应该受到指责。 - Slauma
我手头没有环境,但这个链接可能会有所帮助(如果需要更多信息,我今天稍后会发布答案)- http://msdn.microsoft.com/en-us/library/hh829636(v=vs.103).aspx - 还有可能是这个链接 - http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2b182758-ef29-4407-b62b-12aee816aa45。即,您可以设置自己的`SqlGenerator`,然后有各种SQL生成部分的覆盖 - 但我不确定是否涵盖了您需要的内容。 - NSGaga-mostly-inactive
如果你覆盖 SqlGenerator 并更改名称,你的数据库可能永远不会与 CodeFirst 生成的模型匹配,而且你可能会遇到很多难以解决的奇怪问题。 - Pawel
2个回答

7

由于没有配置约束名称的方法,您需要使用较短的表名。请注意,您不需要更改类名称来实现这一点。您可以使用Table属性或在OnModelCreating中使用.ToTable()方法。


我发布了我心中的实际解决方案 - 链接错误地指向了表格更改(因为我在设备上匆忙操作) - 但我的意思是更改关系名称 - 这应该没有任何后果。如果需要,表名映射仍然是最简单的解决方案 - 完全同意(+1)。 - NSGaga-mostly-inactive
我选择通过注释属性指定一个较短的表名。但这有点糟糕,因为这个项目涉及到其他人使用的基础库。不得不采取这种方式很烦人。我的表名并不是特别长... - Dark Falcon

6

补充一下我之前的评论...

如果你只是想更改表名,那么按照 @Pawel 的建议在 OnModelCreating 中进行映射,这可能是最简单的解决方案。

但是,如果你只想更改关系名称,

...你可以在 Configuration() 中提供自定义的 SqlGenerator(即 SqlServerMigrationSqlGenerator),在需要时微调实际生成的 sql(这可能是某些通用情况下的通用自动化解决方案)。例如:

public class MySqlGenerator : SqlServerMigrationSqlGenerator
{
    protected override void Generate(AddForeignKeyOperation addForeignKeyOperation)
    {
        if (addForeignKeyOperation.Name == "LongClassNameOne_TypeConstraint_From_ClassName2s_To_LongClassNameOnes")
            addForeignKeyOperation.Name = "MyCustomFKName";
        // addForeignKeyOperation.Name = "Test" + addForeignKeyOperation.Name;
        base.Generate(addForeignKeyOperation);
    }
}

...或类似的内容(您需要匹配,找到正确的命名-或比较Name Length并在必要时缩短它。在您的配置文件(由迁移生成)中...

public Configuration()
{
    AutomaticMigrationsEnabled = false;
    SetSqlGenerator("MySqlMigrationSqlGenerator", new MySqlGenerator());
    // SetSqlGenerator("System.Data.SqlClient", new MySqlGenerator());
}

(注:我不确定,但是有人建议(@Mariusz Jamro)MySQL提供程序的名称是MySqlMigrationSqlGenerator,我猜这很有道理)

...这应该会更改关系的FK - 就我快速测试而言,它可以正常工作,因为关系名称在C#模型中并没有真正使用(通常只是一个数据库名称)。


感谢您提供详细的答案,但我想我会缩短表名并接受它。我曾希望有其他解决方案可以缩短该名称,但似乎这是在EF代码中而不是MySQL提供程序中。如果它在MySQL提供程序中,我会选择那个路线,因为我已经需要修复提供程序中的其他2个错误才能使其正常工作。 - Dark Falcon
np - 那很容易我同意 - 修复“关系过长”的正确位置应该在SQL代码生成周围(因为EF/CF生成的这些名称对于MySQL来说太长了,所以MySQL的问题在于它无法接受这些标识符,但EF“导致”了这个问题)。我没有理解你上面的推理。但如果您需要反复进行操作,我会选择“简单的方法”(表名),并采用修复SQL生成的方法。 - NSGaga-mostly-inactive
2
MySQL生成器的名称是MySqlMigrationSqlGenerator - Mariusz Jamro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接