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

posted @ 2019-01-24 17:06  Pen丶  阅读(416)  评论(0编辑  收藏  举报