EF 配置多个数据库
阅读原文时间:2023年07月10日阅读:1

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
{
public AuditLogMap()
{
ToTable("AuditLog");
HasKey(t => t.Id);

        Property(t => t.BrowserInfo).IsOptional().HasColumnType("varchar").HasMaxLength();  
        Property(t => t.ClientIpAddress).IsOptional().HasColumnType("nvarchar").HasMaxLength();  
        Property(t => t.ClientName).IsOptional().HasColumnType("varchar").HasMaxLength();  
        Property(t => t.CustomData).IsOptional().HasColumnType("varchar").HasMaxLength();  
        Property(t => t.Exception).IsOptional().HasColumnType("varchar").HasMaxLength();  
        Property(t => t.ExecutionDuration).IsOptional();  
        Property(t => t.ExecutionTime).IsOptional();  
        Property(t => t.MethodName).IsOptional().HasColumnType("varchar").HasMaxLength();  
        Property(t => t.Parameters).IsOptional().HasColumnType("nvarchar").HasMaxLength();  
        Property(t => t.ServiceName).IsOptional().HasColumnType("varchar").HasMaxLength();  
    }  
}

public abstract class TestProjectRepositoryBase : EfRepositoryBase
where TEntity : class, IEntity
{
protected TestProjectRepositoryBase(IDbContextProvider 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 : EfRepositoryBase
where TEntity : class, IEntity
{
protected TestSecondRepositoryBase(IDbContextProvider 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服务,可以停止。
解决办法: . 在windows控制面版-->管理工具-->服务-->Distributed Transaction Coordinator-->属性-->启动
.在CMD下运行"net start msdtc"开启服务后正常。

注:如果在第1步Distributed Transaction Coordinator 无法启动,则是因为丢失了日志文件,重新创建日志文件,再启动就行了。重新创建 MSDTC 日志,并重新启动服务的步骤如下:
() 单击"开始",单击"运行",输入 cmd 后按"确定"。
() 输入:msdtc -resetlog (注意运行此命令时,不要执行挂起的事务)
() 最后输入:net start msdtc 回车,搞定!