实体框架中数据从一个提供者到另一个提供者的实时传输



如果这个问题已经被问到,我很抱歉,我正在努力了解的术语,因为它与实体框架中的功能相冲突。

我要做的是:

我想创建一个应用程序,在设置时让用户使用1数据库作为"试用"/"启动";数据库,即非生产数据库。这将允许用户试用应用程序,但不会有备份等,这绝不是一个"生产";数据库。例如,可以是SQLite。

当用户准备好了,他们就可以点击"转换到生产"。(或类似),并为其指定新数据库机器/数据库的目标。这将被视为"生产"。环境。可以是MySQL, SQLServer或者…不管现在EF和什么有联系…

问题:

EF是否支持这种类型的迁移/数据实时传输?它是否需要另一个应用程序,您可以在其中配置EF源和EF目的地,然后通过数据源的转换/播种/人口过程运行到另一个数据源?

为什么我在这里问:

我试着搜索关于这个话题的东西,但是转移/迁移带来的主题完全不相关,所以任何帮助都会非常感激。

从你的描述来看,我不认为有什么现成的东西可以支持这一点。您可以将DbContext映射到任何一个数据库,然后从评估DbContext中提取和分离实体,并将它们附加到生产DbContext中。

对于一个相对简单的模式/对象图,这将是相当直接的实现。

ICollection<Customer> customers = new List<Customer>();
using(var context = new AppDbContext(evalConnectionString))
{
customers = context.Customers.AsNoTracking().ToList();
}
using(var context = new AppDbContext(productionConnectionString))
{ // Assuming an empty database...
context.Customers.AddRange(customers);
}

虽然对于更复杂的模型,这可能需要一些工作,特别是在处理诸如现有查找/引用之类的事情时。如果您希望将可能共享相同引用的对象移动到另一个对象,则需要查询目标DbContext以查找现有的亲属,并在保存"父"之前替换它们。实体。

ICollection<Order> orders = new List<Order>();
using(var context = new AppDbContext(evalConnectionString))
{
orders = context.Orders
.Include(x => x.Customer)
.AsNoTracking()
.ToList();
}
using(var context = new AppDbContext(productionConnectionString))
{ 
var customerIds = orders.Select(x => x.Customer.CustomerId)
.Distinct().ToList();
var existingCustomers = context.Customers
.Where(x => customerIds.Contains(x.CustomerId))
.ToList();

foreach(var order in orders)
{  // Assuming all customers were loaded
var existingCustomer = existingCustomers.SingleOrDefault(x => x.CustomerId == order.Customer.CustomerId);
if(existingCustomer != null)
order.Customer = existingCustomer;
else
existingCustomers.Add(order.Customer);
context.Orders.Add(order);
}
}

这是一个非常简单的示例,概述了如何处理这样的场景:您可能会插入带有引用的数据,这些引用可能存在于目标DbContext中,也可能不存在于目标DbContext中。如果我们跨订单进行复制,并希望处理它们各自的客户,我们首先需要检查是否存在任何跟踪的客户引用,并使用该引用来避免插入重复行或抛出异常。

通常从一个DbContext加载订单和相关引用应该确保引用相同Customer实体的多个订单都将共享相同的实体引用。但是,要使用可以通过AsNoTracking()与新DbContext关联的分离实体,对同一记录的分离引用将不是是相同的引用,因此我们需要小心处理这些。

例如,同一客户有两个订单:

var ordersA = context.Orders.Include(x => x.Customer).ToList();
Assert.AreSame(orders[0].Customer, orders[1].Customer); // Passes

var ordersB = context.Orders.Include(x => x.Customer).AsNoTracking().ToList();
Assert.AreSame(orders[0].Customer, orders[1].Customer); // Fails 

尽管在第二个例子中两者都是针对同一个客户。每个都有一个具有相同ID的Customer引用,但是有两个不同的引用,因为DbContext没有跟踪所使用的引用。几个"get tchas"中的一个。通过独立的实体和努力来提高性能等。使用跟踪引用并不理想,因为这些实体仍然认为它们与另一个DbContext相关联。我们可以分离它们,但这意味着要仔细查看对象图并分离所有引用。(可操作,但与只是卸载它们相比比较混乱)

当可能批量迁移数据(定期处理DbContext以避免大数据量的性能缺陷)或随时间同步数据时,情况也会变得复杂。通常建议首先检查目标DbContext中是否有匹配的记录,并使用这些记录来避免插入重复数据。(或抛出异常)

所以简单的数据模型这是相当直接的。对于更复杂的数据,需要传递更多的数据,数据之间的关系也更复杂。对于这些系统,我可能会考虑生成数据库到数据库的迁移,例如从源数据库中的数据为所需的目标DB创建INSERT语句。在这里,只需按照关系顺序插入数据以符合数据约束。(使用工具或滚动您自己的脚本生成)

最新更新