将子实体移动到新的父实体
本文关键字:实体 移动 | 更新日期: 2023-09-27 18:25:15
将子实体从父实体移动到另一个父实体的最佳方式是什么?ObjectContext或DbContext中是否有一种方法可以让我们实现这一点?
public class Person
{
public int PersonId
public ICollection<Car> Cars
}
public class Car
{
public int CarId
public string Color
}
编辑:我目前正在使用EF 4.0模型首先与POCO模板。
我想说,在本例中,您想要实现的是更换车主。如果在Car
中添加对Person
的反向引用没有严重的缺点,我会选择以下内容:
public class Car
{
...
public virtual Person Owner { get; protected set; }
public void ChangeOwner(Person newOwner)
{
// perform validation and then
Owner = newOwner;
// maybe perform some further domain-specific logic
}
}
注意:受保护的setter用于强制外部使用者调用ChangeOwner
方法。EF将能够正确设置它,这要归功于POCO类的自动生成代理(假设您使用它们)。
编辑:如果不可能添加对Person
的反向引用,那么从域逻辑的角度来看,您仍然有相同的目标。你只想换个车主。这样的操作涉及两个实体,所以我可能会选择一个放置在实体外部的方法(不管它应该放在设计良好的系统中的哪里):
public void ChangeCarOwner(Person originalOwner, Person newOwner, int carId)
{
Car car = originalOwner.RemoveCarOwnership(carId);
newOwner.AddCarOwnership(car);
}
public class Person
{
...
public Car RemoveCarOwnership(int carId)
{
Car car = this.Cars.Single(c => c.Id == carId);
this.Cars.Remove(car);
return car;
}
}
这只是一段概念性的代码,当然它可以写得更好(确保老车主真的拥有这辆车等等),但我只是想提出一个如何处理它的想法。我也放弃了AddCarOwnership
的实现,因为我认为它很有局限性。我介绍了这些方法,因为添加和删除所有权可能会在特定的人"内部"触发一些进一步的逻辑。
使用现代EFCore,您可以通过附加新的Parent实体来实现这一点,该实体包含具有ID的子实体。它将重新分配子对象的FK(或者在没有指定ID的情况下创建它),并创建新的Person,所有这些都是一次性
例如:
var newOwner = new Person {
Cars = new List<Car> {
new Car { carId = theCarToMove.carId }
}
};
Context.Attach(newOwner);
await Context.SaveChangesAsync();
注意,如果您的上下文不是真正的瞬态,那么Attach可能会导致问题,但作为一个创可贴,您可以在尝试Attach 之前清除ChangeTracker
编辑:经过尝试,我发现对于一些数据库提供商来说,它不能直接工作。相反,请尝试:
foreach(var car in carsToMove)
{
Context.Attach(car);
car.Owner = newOwner;
}
Context.Attach(newOwner);
await Context.SaveChangesAsync();
使用Attach时,顺序很重要。EFCore构建的SQL查询的构建顺序与您在C#中设置它的顺序相反。如果在cars之前附加newOwner,那么CREATE查询是SQL中的最后一个查询,在cars的UPDATE之后。如果是这种情况,汽车就不能更新到新的OwnerId,因为newOwner在查询中当时没有ID。我相信这也是第一个代码块的情况,一些提供程序