1.先創建兩個DbContext
using System; using System.Data.Common; using System.Data.Entity; using System.Data.Entity.ModelConfiguration; using System.Data.Entity.ModelConfiguration.Conventions; using System.Linq; using System.Reflection; using Abp.EntityFramework; namespace TestProject.EntityFramework { public class TestProjectDbContext : AbpDbContext { //TODO: Define an IDbSet for each Entity... //Example: //public virtual IDbSet<User> Users { get; set; } /* NOTE: * Setting "Default" to base class helps us when working migration commands on Package Manager Console. * But it may cause problems when working Migrate.exe of EF. If you will apply migrations on command line, do not * pass connection string name to base classes. ABP works either way. */ public TestProjectDbContext() : base("Default") { } /* NOTE: * This constructor is used by ABP to pass connection string defined in TestProjectDataModule.PreInitialize. * Notice that, actually you will not directly create an instance of TestProjectDbContext since ABP automatically handles it. */ public TestProjectDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { } //This constructor is used in tests public TestProjectDbContext(DbConnection existingConnection) : base(existingConnection, false) { } public TestProjectDbContext(DbConnection existingConnection, bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection) { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { var typesRegister = Assembly.GetExecutingAssembly().GetTypes() .Where(type => !(string.IsNullOrEmpty(type.Namespace))).Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in typesRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(configurationInstance); } //刪除級聯 modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); base.OnModelCreating(modelBuilder); } } }
下面是新建的上下文,新建的DbContext不能含有DbContext(string nameOrConnectionString)構造函數,否則會被默認的連接名注入。
using Abp.EntityFramework; using System; using System.Collections.Generic; using System.Data.Common; using System.Data.Entity; using System.Data.Entity.ModelConfiguration; using System.Data.Entity.ModelConfiguration.Conventions; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace TestProject.EntityFramework { public class TestSecondDbContext : AbpDbContext { //TODO: Define an IDbSet for each Entity... public DbSet<AuditLog> AuditLog { get; set; } //Example: //public virtual IDbSet<User> Users { get; set; } /* NOTE: * Setting "Default" to base class helps us when working migration commands on Package Manager Console. * But it may cause problems when working Migrate.exe of EF. If you will apply migrations on command line, do not * pass connection string name to base classes. ABP works either way. */ public TestSecondDbContext() : base("Second") { } //This constructor is used in tests public TestSecondDbContext(DbConnection existingConnection) : base(existingConnection, false) { } public TestSecondDbContext(DbConnection existingConnection, bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection) { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { var typesRegister = Assembly.GetExecutingAssembly().GetTypes() .Where(type => !(string.IsNullOrEmpty(type.Namespace))).Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in typesRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(configurationInstance); } //刪除級聯 modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); base.OnModelCreating(modelBuilder); } } }
2.創建實體類並且配置映射
public class AuditLogMap : EntityTypeConfiguration<AuditLog> { public AuditLogMap() { ToTable("AuditLog"); HasKey(t => t.Id); Property(t => t.BrowserInfo).IsOptional().HasColumnType("varchar").HasMaxLength(512); Property(t => t.ClientIpAddress).IsOptional().HasColumnType("nvarchar").HasMaxLength(64); Property(t => t.ClientName).IsOptional().HasColumnType("varchar").HasMaxLength(128); Property(t => t.CustomData).IsOptional().HasColumnType("varchar").HasMaxLength(2000); Property(t => t.Exception).IsOptional().HasColumnType("varchar").HasMaxLength(2000); Property(t => t.ExecutionDuration).IsOptional(); Property(t => t.ExecutionTime).IsOptional(); Property(t => t.MethodName).IsOptional().HasColumnType("varchar").HasMaxLength(256); Property(t => t.Parameters).IsOptional().HasColumnType("nvarchar").HasMaxLength(1024); Property(t => t.ServiceName).IsOptional().HasColumnType("varchar").HasMaxLength(256); } }
public abstract class TestProjectRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<TestProjectDbContext, TEntity, TPrimaryKey> where TEntity : class, IEntity<TPrimaryKey> { protected TestProjectRepositoryBase(IDbContextProvider<TestProjectDbContext> dbContextProvider) : base(dbContextProvider) { } //add common methods for all repositories } public abstract class TestProjectRepositoryBase<TEntity> : TestProjectRepositoryBase<TEntity, int> where TEntity : class, IEntity<int> { protected TestProjectRepositoryBase(IDbContextProvider<TestProjectDbContext> dbContextProvider) : base(dbContextProvider) { } //do not add any method here, add to the class above (since this inherits it) }
public abstract class TestSecondRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<TestSecondDbContext, TEntity, TPrimaryKey> where TEntity : class, IEntity<TPrimaryKey> { protected TestSecondRepositoryBase(IDbContextProvider<TestSecondDbContext> dbContextProvider) : base(dbContextProvider) { } //add common methods for all repositories } public abstract class TestSecondRepositoryBase<TEntity> : TestSecondRepositoryBase<TEntity, int> where TEntity : class, IEntity<int> { protected TestSecondRepositoryBase(IDbContextProvider<TestSecondDbContext> dbContextProvider) : base(dbContextProvider) { } //do not add any method here, add to the class above (since this inherits it) }
3.執行命令
First step ========== enable-migrations -ContextTypeName TestProjectDbContext -MigrationsDirectory Migrations enable-migrations -ContextTypeName TestSecondDbContext -MigrationsDirectory MigrationsSecond Second Step =========== add-migration -ConfigurationTypeName TestProject.Migrations.Configuration "InitialCreate" "InitialCreate" add-migration -ConfigurationTypeName TestProject.MigrationsSecond.Configuration "InitialCreate" Third Step ========== update-database -ConfigurationTypeName TestProject.Migrations.Configuration -verbose update-database -ConfigurationTypeName TestProject.MigrationsSecond.Configuration -verbose
4 開啟MSDTC
MSDTC(分布式交易協調器),協調跨多個數據庫、消息隊列、文件系統等資源管理器的事務。該服務的進程名為Msdtc.exe,該進程調用系統Microsoft Personal Web Server和Microsoft SQL Server。該服務用於管理多個服務器 . 位置:控制面板--管理工具--服務--Distributed Transaction Coordinator 依存關系:Remote Procedure Call(RPC)和Security Accounts Manager 建議:一般家用計算機涉及不到,除非你啟用Message Queuing服務,可以停止。 解決辦法: 1. 在windows控制面版-->管理工具-->服務-->Distributed Transaction Coordinator-->屬性-->啟動 2.在CMD下運行"net start msdtc"開啟服務后正常。 注:如果在第1步Distributed Transaction Coordinator 無法啟動,則是因為丟失了日志文件,重新創建日志文件,再啟動就行了。重新創建 MSDTC 日志,並重新啟動服務的步驟如下: (1) 單擊"開始",單擊"運行",輸入 cmd 后按"確定"。 (2) 輸入:msdtc -resetlog (注意運行此命令時,不要執行掛起的事務) (3) 最后輸入:net start msdtc 回車,搞定!