📜  如何为多个上下文启用 EF 迁移到单独的数据库? (1)

📅  最后修改于: 2023-12-03 15:08:13.109000             🧑  作者: Mango

如何为多个上下文启用 EF 迁移到单独的数据库?

在某些情况下,您可能需要使用多个上下文来管理您的实体。 对于这些情况,您可能需要将这些上下文迁移到单独的数据库。本指南将向您介绍如何使用 Entity Framework 来为多个上下文启用迁移到单独数据库的功能。

有两种方法可以实现此目的:

  1. 使用分离器
  2. 在每个上下文中配置单独的数据库
使用分离器

分离器是一种用于将实体分配到单独数据库的机制。 Entity Framework 使用分离器来将上下文中的实体映射到不同的数据库。这是一种非常灵活的方法,它使您能够对实体进行更细粒度的控制。

配置分离器

首先,您需要在您的代码中配置分离器。以下是一个示例:

public class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("<schema>");

        modelBuilder.Entity<MyEntity>().ToTable("<table-name>", "<schema>");
            .HasData(new MyEntity { ... });
            ...
        modelBuilder.Entity<MyOtherEntity>().ToTable("<other-table-name>", "<schema>");
            .HasData(new MyOtherEntity { ... });
            ...
    }

    public DbSet<MyEntity> MyEntities { get; set; }
    public DbSet<MyOtherEntity> MyOtherEntities { get; set; }
}

在这个例子中,我们可以看到从 DbSet 生成到菜单的 Entity 都被指定为与表< table-name >以及< schema >架构中,同时,可以使用 HasData 来指定种子数据。

有了这些配置,我们可以将实体存储到不同的数据库中。您需要配置如下所示的数据上下文:

public class MyContextA : MyContext
{
    public MyContextA() : base(new DbContextOptionsBuilder<MyContext>()
        .UseSqlServer("<connection-string-target-database>")
        .Options) { }
}

public class MyContextB : MyContext
{
    public MyContextB() : base(new DbContextOptionsBuilder<MyContext>()
        .UseSqlServer("<connection-string-target-database-2>")
        .Options) { }
}

在这个例子中,我们创建了两个数据上下文:MyContextA 和 MyContextB,每个上下文都有不同的连接字符串,连接到不同的数据库。

处理实体分离

当您使用上述配置来配置分离器时,您需要确保正确地处理实体分离。这是因为您不能简单地将实体从一个上下文复制到另一个上下文中。您需要使用以下方法之一来处理实体分离:

  1. 使用领域模型: 在这种方法中,您需要使用领域模型来清晰地定义实体之间的关系。这有助于确保您可以将实体从一个上下文中删除而不会影响到其他上下文。

  2. 使用 DTO(数据传输对象):使用此方法时,您需要创建一些专门用于数据传输的类。这些类只传递数据,而不包含任何业务逻辑。这使您能够将数据从一个上下文复制到另一个上下文中,而不会影响到其他上下文。

领域模型实现方式

在这个例子中,我们使用一个领域模型来处理实体分离。以下是一个示例:

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public Customer Customer { get; set; }
    public ICollection<OrderItem> Items { get; set; }
}

public class OrderItem
{
    public int Id { get; set; }
    public string Description { get; set; }
    public int OrderId { get; set; }
    public Order Order { get; set; }
}

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options) : base(options) { }

    public DbSet<Order> Orders { get; set; }
    public DbSet<Customer> Customers { get; set; }
    public DbSet<OrderItem> OrderItems { get; set; }
}

在这个例子中,我们使用一个领域模型来清晰地定义实体之间的关系。我们还创建了一个名为 MyContext 的数据上下文,并为每个实体创建一个 DbSet 字段。

DTO实现方式

在这个例子中,我们使用一个 DTO(数据传输对象)来处理实体分离。以下是一个示例:

public class OrderDto
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public ICollection<OrderItemDto> Items { get; set; }
}

public class OrderItemDto
{
    public int Id { get; set; }
    public string Description { get; set; }
}

public class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options) : base(options) { }

    public DbSet<OrderDto> Orders { get; set; }
    public DbSet<OrderItemDto> OrderItemDtos { get; set; }
}

在这个例子中,我们创建了用于传输数据的 DTO。我们还创建了一个名为 MyContext 的数据上下文,并为每个 DTO 创建了一个 DbSet 字段。

执行具视操作

一旦您已经配置好分离器并正确地处理了实体分离,您就可以开始执行 CRUD 操作了。以下是一个示例:

var contextA = new MyContextA();
var contextB = new MyContextB();

var order = new Order
{
    Id = 1,
    CustomerId = 1,
    Items = new List<OrderItem>
    {
        new OrderItem
        {
            Id = 1,
            Description = "Item 1"
        },
        new OrderItem
        {
            Id = 2,
            Description = "Item 2"
        }
    }
};

contextA.Orders.Add(order);
contextA.SaveChanges();

var orderDto = new OrderDto 
{
    Id = order.Id, 
    CustomerId = order.CustomerId,
    Items = order.Items.Select(i => new OrderItemDto() { Id = i.Id, Description = i.Description }).ToList()
};

contextB.Orders.Add(orderDto);
contextB.SaveChanges();

在这个例子中,我们创建了一个 Order 实体,并将其添加到 contextA 的 Orders 集合中。然后,我们从 Order 实体创建一个 OrderDto,并将其添加到 contextB 的 Orders 集合中。最后,我们保存每个上下文并检查它们是否正常工作。

在每个上下文中配置单独的数据库

一种更简单的方法是在每个上下文中配置单独的数据库。这种方法不需要使用分离器,并且可以更轻松地处理实体分离。

配置每个上下文

如下所示,您可以通过在每个上下文中使用不同的连接字符串来配置单独的数据库:

public class MyContextA : DbContext
{
    public MyContextA() : base(new DbContextOptionsBuilder<MyContext>()
        .UseSqlServer("<connection-string-target-database>")
        .Options) { }
}

public class MyContextB : DbContext
{
    public MyContextB() : base(new DbContextOptionsBuilder<MyContext>()
        .UseSqlServer("<connection-string-target-database-2>")
        .Options) { }
}

在这个例子中,我们创建了两个数据上下文:MyContextA 和 MyContextB,每个上下文都有不同的连接字符串,连接到不同的数据库。

执行具视操作

一旦您已经配置好每个上下文并正确地处理了实体分离,您就可以开始执行 CRUD 操作了。以下是一个示例:

var contextA = new MyContextA();
var contextB = new MyContextB();

var order = new Order
{
    Id = 1,
    CustomerId = 1,
    Items = new List<OrderItem>
    {
        new OrderItem
        {
            Id = 1,
            Description = "Item 1"
        },
        new OrderItem
        {
            Id = 2,
            Description = "Item 2"
        }
    }
};

contextA.Orders.Add(order);
contextA.SaveChanges();

var order2 = new Order
{
    Id = 2,
    CustomerId = 2,
    Items = new List<OrderItem>
    {
        new OrderItem
        {
            Id = 1,
            Description = "Item 1"
        },
        new OrderItem
        {
            Id = 2,
            Description = "Item 2"
        },
        new OrderItem
        {
            Id = 3,
            Description = "Item 3"
        }
    }
};

contextB.Orders.Add(order2);
contextB.SaveChanges();

在这个例子中,我们创建了两个 Order 实体,并将其添加到 contextA 和 contextB 的 Orders 集合中。最后,我们保存每个上下文并检查它们是否正常工作。

总结

无论您是使用分离器还是使用每个上下文的单独数据库,都应该可以轻松地管理多个上下文和实体。如果您选择使用分离器,请确保正确地处理实体分离,并根据需要执行相应的操作。如果您选择使用每个上下文的单独数据库,请确保为每个上下文提供正确的连接字符串。通过使用这些简单的技术,您将能够使用 Entity Framework 效率地管理大量的实体和上下文。