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 回车,搞定!