CodeFirst(一)一个简单的Mysql例子
一个简单的例子
1: 新建实体
public class MUserInfo
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
2: 新建Context
// [DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
// 可以配置文件进行配置(codeConfigurationType)
public class SwartzUserUserContext : DbContext
{
//使用UserContext connectionString
public SwartzUserUserContext():base("UserContext")
{
}
public DbSet<MUserInfo> UserInfo { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//移除将表名称设置为实体名称的约定
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//表名加swartz前缀
modelBuilder.Types().Configure(f => f.ToTable("swartz" + f.ClrType.Name));
}
}
3: 初始化数据
public class DataModelInitializer : DropCreateDatabaseIfModelChanges<SwartzUserUserContext>
{
protected override void Seed(SwartzUserUserContext context)
{
//初始化数据
context.UserInfo.Add(new MUserInfo
{
ID = 1,
Age = 12,
Name = "dzjx"
});
context.SaveChanges();
base.Seed(context);
}
}
4: 修改配置文件
<?xml version="1.0" encoding="utf-8"?>
<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>
<connectionStrings>
<add name="UserContext" connectionString="Server=localhost;User ID=root;Password=root;Database=SwartzUser" providerName="MySql.Data.MySqlClient"/>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<!--必须指定类型 否则默认当成sql server 否则会报错误 Specified key was too long; max key length is 767 bytes-->
<entityFramework codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration, MySql.Data.Entity.EF6">
<!--指定实体类,以及初始化的类 -->
<contexts>
<context type="CodeFirst.Model.SwartzUserUserContext,CodeFirst" disableDatabaseInitialization="false" >
<databaseInitializer type="CodeFirst.Model.DataModelInitializer,CodeFirst">
</databaseInitializer>
</context>
</contexts>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v13.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"></provider>
</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.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
</configuration>
5: 运行即可自动生成表了....
注意:在使用mysql的时候配置文件必须指定codeConfigurationType(或者通过添加SwartzUserUserContext注解DbConfigurationType) 否则会报错Specified key was too long; max key length is 767 bytes,原因是使用codefirst 会默认生成__migrationhistory表,表的默认主键导致,具体的如下:
// ef源码
public class MySqlEFConfiguration : DbConfiguration
{
// Methods
public MySqlEFConfiguration()
{
base.AddDependencyResolver(new MySqlDependencyResolver());
base.SetProviderFactory(MySqlProviderInvariantName.ProviderName, new MySqlClientFactory());
base.SetProviderServices(MySqlProviderInvariantName.ProviderName, new MySqlProviderServices());
base.SetDefaultConnectionFactory(new MySqlConnectionFactory());
base.SetMigrationSqlGenerator(MySqlProviderInvariantName.ProviderName, <>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Func<MigrationSqlGenerator>(<>c.<>9.<.ctor>b__0_0)));
base.SetProviderFactoryResolver(new MySqlProviderFactoryResolver());
base.SetManifestTokenResolver(new MySqlManifestTokenResolver());
base.SetHistoryContext(MySqlProviderInvariantName.ProviderName, <>c.<>9__0_1 ?? (<>c.<>9__0_1 = new Func<DbConnection, string, HistoryContext>(<>c.<>9.<.ctor>b__0_1)));
}
// Nested Types
[Serializable, CompilerGenerated]
private sealed class <>c
{
// Fields
public static readonly MySqlEFConfiguration.<>c <>9 = new MySqlEFConfiguration.<>c();
public static Func<MigrationSqlGenerator> <>9__0_0;
public static Func<DbConnection, string, HistoryContext> <>9__0_1;
// Methods
internal MigrationSqlGenerator <.ctor>b__0_0()
{
return new MySqlMigrationSqlGenerator();
}
internal HistoryContext <.ctor>b__0_1(DbConnection existingConnection, string defaultSchema)
{
return new MySqlHistoryContext(existingConnection, defaultSchema);
}
}
}
如源码所示:在没有指定codeConfigurationType的情况下,ef 默认使用HistoryContext,在该上下文中对History(__migrationhistory)表的处理如下
public class HistoryContext : DbContext, IDbModelCacheKeyProvider
{
// Fields
private readonly string _defaultSchema;
internal const int ContextKeyMaxLength = 300;
internal static readonly Func<DbConnection, string, HistoryContext> DefaultFactory = (e, d) => new HistoryContext(e, d);
public const string DefaultTableName = "__MigrationHistory";
internal const int MigrationIdMaxLength = 150;
// Methods
[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
internal HistoryContext()
{
this.InternalContext.InitializerDisabled = true;
}
[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public HistoryContext(DbConnection existingConnection, string defaultSchema) : base(existingConnection, false)
{
this._defaultSchema = defaultSchema;
base.Configuration.ValidateOnSaveEnabled = false;
this.InternalContext.InitializerDisabled = true;
}
[CompilerGenerated]
private static HistoryContext <.cctor>b__0(DbConnection e, string d)
{
return new HistoryContext(e, d);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema(this._defaultSchema);
modelBuilder.Entity<HistoryRow>().ToTable("__MigrationHistory");
modelBuilder.Entity<HistoryRow>().HasKey(h => new { MigrationId = h.MigrationId, ContextKey = h.ContextKey });
modelBuilder.Entity<HistoryRow>().Property((Expression<Func<HistoryRow, string>>) (h => h.MigrationId)).HasMaxLength(150).IsRequired();
modelBuilder.Entity<HistoryRow>().Property((Expression<Func<HistoryRow, string>>) (h => h.ContextKey)).HasMaxLength(300).IsRequired();
modelBuilder.Entity<HistoryRow>().Property((Expression<Func<HistoryRow, byte[]>>) (h => h.Model)).IsRequired().IsMaxLength();
modelBuilder.Entity<HistoryRow>().Property((Expression<Func<HistoryRow, string>>) (h => h.ProductVersion)).HasMaxLength(0x20).IsRequired();
}
// Properties
public virtual string CacheKey
{
get
{
return this._defaultSchema;
}
}
protected string DefaultSchema
{
get
{
return this._defaultSchema;
}
}
public virtual IDbSet<HistoryRow> History { get; set; }
}
从代码中看出主键是MigrationId + ContextKey 从代码中看出长度已经450(150+300)咯,而默认情况下InnoDB 引擎单一字段索引的长度最大为 767 字节,索引已经超过mysql索引范围咯(utf-8编码的话 为450*3 > 767),所以就报错了,当我们指定 codeConfigurationType 为MySql.Data.Entity.MySqlEFConfiguration 后可以看见MySqlHistoryContext 继承了HistoryContext,并修改了主键
public class MySqlHistoryContext : HistoryContext
{
// Methods
public MySqlHistoryContext(DbConnection existingConnection, string defaultSchema) : base(existingConnection, defaultSchema)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
ParameterExpression expression;
base.OnModelCreating(modelBuilder);
Expression[] arguments = new Expression[] { Expression.Property(expression = Expression.Parameter(typeof(HistoryRow), "h"), (MethodInfo) methodof(HistoryRow.get_MigrationId)) };
MemberInfo[] members = new MemberInfo[] { (MethodInfo) methodof(<>f__AnonymousType0<string>.get_MigrationId, <>f__AnonymousType0<string>) };
ParameterExpression[] parameters = new ParameterExpression[] { expression };
modelBuilder.Entity<HistoryRow>().HasKey(Expression.Lambda(Expression.New((ConstructorInfo) methodof(<>f__AnonymousType0<string>..ctor, <>f__AnonymousType0<string>), arguments, members), parameters));
}
}
从如上代码可知,现在的主键只有MigrationId,长度只用150 所以完成支持了
EF源码地址:
http://entityframework.codeplex.com/
https://github.com/aspnet/EntityFramework