实体框架以一对多替换集合的正确方法

时间:2015-05-08 05:06:51

标签: c# entity-framework orm mapping entity-framework-6

假设客户有多个电话号码,而电话号码只有一个客户。

public class PhoneNumber : IValueObject {
  public string Number {get; set;}
  public string Type {get; set;}
}

public class Customer : IEntity {
   public ICollection<PhoneNumber> phones {get; private set;} //ew at no encapsulated collection support
   public void SetPhones(params PhoneNumber[] phones) {
       this.phones.Clear();
       this.phones.AddRange(phones);
   }
}

如果我像这样进行EF映射并运行它,每次设置电话号码时都会创建新的PhoneNumbers但不删除旧的。没有其他实体引用电话号码,我甚至没有在我的dbcontext上公开它,有没有办法告诉EF Customer完全拥有PhoneNumbers,因此如果从集合中删除了电话号码它们应该被删除?

proof

我意识到有十几种方法来解决这个问题,但这不是一个奇怪的边缘情况,处理这个问题的“正确”方法是什么。

2 个答案:

答案 0 :(得分:9)

我有完全相同的问题:)

identifying relationships上的这个答案解决了我的问题。

注意:您必须加载集合(热切,明确或懒惰),以便在设置新值和调用save之前对其进行跟踪。否则你不会更换集合,只是添加它。

例如:

var entity = unitOfWork.EntityRepository.GetById(model.Id);
// I have something like this to load collection because
// I don't have the collection's entities exposed to the context
unitOfWork.EntityRepository.LoadCollection(entity, e => e.CollectionProperty);
entity.CollectionProperty = newCollectionValuesList;
unitOfWork.Save();

这将从'集合表'中删除以前的集合值,并仅添加新设置的值。

希望有所帮助。

答案 1 :(得分:1)

首先(可选):

我建议你做

public ICollection<PhoneNumber> phones {get; private set;}

virtual属性,让 Entity Framework 知道它应该是延迟加载的(即使你没有启用 Lazy Load ,它也是一个好的做法)。

public virtual ICollection<PhoneNumber> phones {get; private set;}

<强>第二

PhoneNumber课程中添加反向导航属性(它将必需,以便实现我在下面提供的解决方案):

public class PhoneNumber : IValueObject {
  public string Number {get; set;}
  public string Type {get; set;}

  public virtual Customer {get; set;}
}

public class Customer : IEntity {
   public ICollection<PhoneNumber> phones {get; private set;} //ew at no encapsulated collection support
   public void SetPhones(params PhoneNumber[] phones) {
       this.phones.Clear();
       this.phones.AddRange(phones);
   }
}

第三个(问题的可能解决方案):

从Context中删除PhoneNumber个对象,而不是从Customer

执行此操作
public ICollection<PhoneNumber> phones {get; private set;} //ew at no encapsulated collection support
   public void SetPhones(params PhoneNumber[] phones) {
       Context.PhoneNumbers.RemoveRange(this.phones);
       this.phones.AddRange(phones);
   }
}