專案因成本考慮需從 SQL Server 遷移至 MySQL。本文記錄在 .NET Framework 4.x + EF 6.1.3 環境下,使用 MySql.Data.Entity 6.9.8 實現 Code First 自動建庫的完整步驟、關鍵配置與踩過的坑。
EntityFramework 6.1.3、MySql.Data.Entity 6.9.8utf8mb4 字符集,支援 Emoji)Install-Package EntityFramework -Version 6.1.3 Install-Package MySql.Data.Entity -Version 6.9.8
public class User
{
public int Id { get; set; }
[StringLength(30)] // 必須指定長度,否則映射為 LONGTEXT 導致「Specified key was too long; max key length is 767 bytes」
public string UserName { get; set; }
[MaxLength(30)]
public string PassWord { get; set; }
}
原因:MySQL InnoDB 單列索引最大 767 bytes(utf8mb4 下 255 字符),EF 預設 string 映射為 LONGTEXT,無法建立索引。務必用 StringLength 或 MaxLength 限制長度。
[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class MyContext : DbContext
{
public MyContext() : base("name=MyContext") { }
public DbSet<User> Users { get; set; }
}
[DbConfigurationType(typeof(MySqlEFConfiguration))]:告訴 EF 使用 MySQL 提供者,自動註冊解析器、遷移生成器等。MyContext,對應 Web.config 中的 connectionStrings。<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
<connectionStrings>
<add name="MyContext" connectionString="Server=localhost;Port=3306;Database=MySQL_EF;Uid=root;Pwd=root;Charset=utf8mb4;" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
</configuration>
關鍵點:
provider 節點的 type 必須精確到版本號與 PublicKeyToken,否則運行時找不到提供者。DbProviderFactories 先 remove 再 add,避免機器級配置衝突。Charset=utf8mb4。Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
using (var ctx = new MyContext())
{
ctx.Users.Add(new User { UserName = "EF6MySQL" });
ctx.SaveChanges();
}
運行程式,MySQL 自動建立 MySQL_EF 資料庫與 Users 表。
| 錯誤訊息 | 原因 | 解決 |
|---|---|---|
| Specified key was too long; max key length is 767 bytes | 字符串屬性未限制長度,映射為 LONGTEXT | 加 [StringLength(n)] 或 [MaxLength(n)] |
| Model compatibility cannot be checked because the database does not contain model metadata | 資料庫與模型不一致(如手動刪表) | 刪除資料庫重跑、或啟用 Migrations |
| 序列不包含任何匹配元素 | 外鍵/導航屬性配置錯誤 | 檢查 [ForeignKey]、HasOptional/HasMany 配對 |
| ProviderIncompatibleException | DbConfigurationType 缺失或版本不匹配 | 補全 Attribute、核對 NuGet 版本 |
// 正確:自引用多對一
public class Employee
{
[Key] public int EmployeeId { get; set; }
public string Name { get; set; }
[ForeignKey("ManagerId")]
public virtual Employee Manager { get; set; }
public int? ManagerId { get; set; } // 可空,避免循環依賴
}
// Fluent API 進階
modelBuilder.Entity<Category>()
.HasKey(c => c.IdCategory)
.HasMany(p => p.Children) // 一對多
.WithOptional() // 子端可無父
.HasForeignKey(c => c.ChildrenId);
virtual 支援延遲加載。int?),頂層節點 ManagerId = NULL。WithMany() 與 WithOptional() 混淆,HasMany 對應 WithOptional/WithRequired。StringLength/MaxLength)。Web.config 提供者註冊版本號、PublicKeyToken 必須與 NuGet 包完全一致。Enable-Migrations 管理結構變更,避免 DropCreateDatabaseIfModelChanges 導致數據丟失。