EF6 仅使用它的 Id 将实体添加到集合
EF6 Add entity to a collection only using it's Id
我有一个问题,我需要通过从 EF 读取实体来将它添加到集合中。
因为集合所属的实体稍后会添加到另一个上下文中。
例子
实体事件被创建并保存到 EFContext 1 并获得 ID 1。
事件需要保存在这里,稍后添加到集合中。
实体汽车已创建但未添加或保存到上下文中。
汽车在几个功能之间传递,并在用户单击按钮后传递。
Car 被传递给另一个 class 并添加到第二个 DBContext (2)。
或者可能是用户取消了,汽车没有保存,事件仍然存在,证明它发生了。
Car 的事件集合为 属性。
我想将 Event 添加到此集合中,但只能通过使用它的 ID,因为汽车稍后由另一个 DBContext 2 添加和保存。
通常我想从当前的 DBContext 加载事件并将其添加到汽车实体。但是随后两个 DBContexts 混合在一起。
我想要的是 Car.Events.Add(new Event() {EventId == 1});
但这想创建一个新事件,这不是我想要的。
我无法访问关系 table(通过 EF),因为 EF 是生成的。
我想要的有可能吗?
有些选项可能适合您的场景,但我建议您在使用有界上下文时要谨慎,而不接受在引用它们的每个上下文中加载实体的成本。如果一个 DbContext 创建了一个事件,而另一个 DbContext 创建了一辆您想绑定到该现有事件的汽车,知道该事件 ID,您可以执行如下操作:
using (var carContext = new CarContext())
{
var event = new Event { Id = eventId };
carContext.Events.Attach(event);
var car = new Car { /* ... */ };
car.Events.Add(event);
carContext.SaveChanges();
}
如果第二个上下文更多 long-lived,例如范围为 Web 请求等,那么您应该在附加事件之前首先使用该引用搜索事件的上下文。
Event event = carContext.Events.Local.SingleOrDefault(x => x.Id == eventId);
if (event == null)
{
event = new Event { Id = eventId };
carContext.Events.Attach(event);
}
// ...
如果该事件没有持久化,或者在调用此代码之前已被删除,这将在 SaveChanges 上引发异常。
通常,如果我有限界上下文,其中汽车上下文需要了解事件,但只关心 reading/associating 汽车,并且只需要几列,我将简化的事件实体模型映射到只包含我需要的字段的事件,然后我可以在上下文中廉价地加载这些。例如,如果事件 table 有 30 列,但就 Cars 而言,我只需要事件的 ID、名称和日期时间,我的 CarContext 将映射一个仅包含这 3 列的轻量级事件实体,而不是完整的事件实体定义。这样我的汽车上下文就可以安全且廉价地加载和关联该事件:
using (var carContext = new CarContext())
{
var event = carContext.Single(x => x.Id == eventId); // Selects 3 columns from DB or can load from cache for longer-lived contexts. I get an exception here if the Event doesn't exist rather than SaveChanges.
var car = new Car { /* ... */ };
car.Events.Add(event);
carContext.SaveChanges();
}
需要注意的是,这个轻量级事件不能用于创建事件行,除非它拥有所有 non-null-able 字段,即使这样也只有一个 DbContext 应该负责插入任何 non-trivial 实体。对于轻量级,我通常在这些实体的名称前加上 "Lw" 前缀,即"LwEvent"。这些实体有注释 header 表明它们不用于插入。
我有一个问题,我需要通过从 EF 读取实体来将它添加到集合中。 因为集合所属的实体稍后会添加到另一个上下文中。
例子 实体事件被创建并保存到 EFContext 1 并获得 ID 1。 事件需要保存在这里,稍后添加到集合中。
实体汽车已创建但未添加或保存到上下文中。 汽车在几个功能之间传递,并在用户单击按钮后传递。 Car 被传递给另一个 class 并添加到第二个 DBContext (2)。 或者可能是用户取消了,汽车没有保存,事件仍然存在,证明它发生了。
Car 的事件集合为 属性。 我想将 Event 添加到此集合中,但只能通过使用它的 ID,因为汽车稍后由另一个 DBContext 2 添加和保存。
通常我想从当前的 DBContext 加载事件并将其添加到汽车实体。但是随后两个 DBContexts 混合在一起。
我想要的是 Car.Events.Add(new Event() {EventId == 1});
但这想创建一个新事件,这不是我想要的。
我无法访问关系 table(通过 EF),因为 EF 是生成的。
我想要的有可能吗?
有些选项可能适合您的场景,但我建议您在使用有界上下文时要谨慎,而不接受在引用它们的每个上下文中加载实体的成本。如果一个 DbContext 创建了一个事件,而另一个 DbContext 创建了一辆您想绑定到该现有事件的汽车,知道该事件 ID,您可以执行如下操作:
using (var carContext = new CarContext())
{
var event = new Event { Id = eventId };
carContext.Events.Attach(event);
var car = new Car { /* ... */ };
car.Events.Add(event);
carContext.SaveChanges();
}
如果第二个上下文更多 long-lived,例如范围为 Web 请求等,那么您应该在附加事件之前首先使用该引用搜索事件的上下文。
Event event = carContext.Events.Local.SingleOrDefault(x => x.Id == eventId);
if (event == null)
{
event = new Event { Id = eventId };
carContext.Events.Attach(event);
}
// ...
如果该事件没有持久化,或者在调用此代码之前已被删除,这将在 SaveChanges 上引发异常。
通常,如果我有限界上下文,其中汽车上下文需要了解事件,但只关心 reading/associating 汽车,并且只需要几列,我将简化的事件实体模型映射到只包含我需要的字段的事件,然后我可以在上下文中廉价地加载这些。例如,如果事件 table 有 30 列,但就 Cars 而言,我只需要事件的 ID、名称和日期时间,我的 CarContext 将映射一个仅包含这 3 列的轻量级事件实体,而不是完整的事件实体定义。这样我的汽车上下文就可以安全且廉价地加载和关联该事件:
using (var carContext = new CarContext())
{
var event = carContext.Single(x => x.Id == eventId); // Selects 3 columns from DB or can load from cache for longer-lived contexts. I get an exception here if the Event doesn't exist rather than SaveChanges.
var car = new Car { /* ... */ };
car.Events.Add(event);
carContext.SaveChanges();
}
需要注意的是,这个轻量级事件不能用于创建事件行,除非它拥有所有 non-null-able 字段,即使这样也只有一个 DbContext 应该负责插入任何 non-trivial 实体。对于轻量级,我通常在这些实体的名称前加上 "Lw" 前缀,即"LwEvent"。这些实体有注释 header 表明它们不用于插入。