我有以下StandardContact实体框架更新许多一对多的关系 - POCO
实体两个实体RelayConfig和之间的许多一对多的关系:
public class RelayConfig : EntityBase, IDataErrorInfo {
...
//Associations
public virtual ICollection<StandardContact> StandardContacts { get; set; }
}
public class StandardContact :EntityBase, IDataErrorInfo {
...
//Associations
public virtual ICollection<RelayConfig> RelayConfigs { get; set; }
}
现在我我试图更新RelayConfig及其与StandardContact的关系。这是更新RelayConfig的代码。
public class RelayConfigRepository : GenericRepository<RelayConfig> {
....
public void Update(RelayConfig relayConfig, List<StandardContact> addedContacts, List<StandardContact> deletedContacts) {
context.RelayConfigs.Add(relayConfig);
if (relayConfig.Id > 0) {
context.Entry(relayConfig).State = EntityState.Modified;
}
addedContacts.ForEach(ad => relayConfig.StandardContacts.Add(ad));
foreach (StandardContact standardContact in relayConfig.StandardContacts) {
if (standardContact.Id > 0) {
context.Entry(standardContact).State = EntityState.Modified;
}
}
relayConfig.StandardContacts.ToList().ForEach(s => {
if (deletedContacts.Any(ds => ds.Id == s.Id)) {
context.Entry(s).State = EntityState.Deleted;
}
});
}
...
}
当我运行更新时,我收到异常,其内部异常如下。
InnerException: System.Data.SqlClient.SqlException
Message=Violation of PRIMARY KEY constraint 'PK__Standard__EE33D91D1A14E395'. Cannot insert duplicate key in object 'dbo.StandardContactRelayConfigs'.
dbo.StandardContactRelayConfigs是链接RelayConfig和StandardContact链接表。如您所见,如果Id> 0(更新方法末尾设置的已删除记录除外),则更新代码会将所有实体更改为已修改状态。
我真的不明白为什么实体框架试图在链接的表中插入行,并与上述例外失败。我已经将现有的RelayConfig.StandardContacts实体的EntityState更改为Modified。
总之,为什么我会得到上面粘贴的异常。
关于, Nirvan。
编辑: 到更新上述(addedContacts和deletedContacts)方法的参数是已经存在的实体ID> 0
EDIT2: 按照您我建议移除用于插入新鲜的代码(不存在于数据库中)记录来自更新方法。所以现在我的更新方法只会将现有的StandardContact记录添加到RelayConfig集合中。但我仍然无法让代码正常工作。首先这里是我使用的代码
public void Update(RelayConfig relayConfig, List<StandardContact> addedContacts, List<StandardContact> deletedContacts) {
context.RelayConfigs.Add(relayConfig);
if (relayConfig.Id > 0) {
context.Entry(relayConfig).State = EntityState.Modified;
}
addedContacts.ForEach(contact => {
context.StandardContacts.Attach(contact);
relayConfig.StandardContacts.Add(contact);
objectContext.ObjectStateManager.
ChangeRelationshipState(relayConfig, contact, rs => rs.StandardContacts, EntityState.Added);
});
}
现在我只是专注于添加记录。当StandardContact(联系变量)与任何其他现有RelayConfig对象没有任何关系时,上面的代码运行良好。在这种情况下,在联接表中为每个添加到RelayConfig.StandardContacts集合的联系人创建一个新条目。但是当StandardContact(联系变量)已经与其他RelayConfig对象有关系时,事情变得很难理解(不可预知的行为)。在这种情况下,当StandardContact添加到RelayConfig.StandardContacts集合中时,StandardContact也会被添加到数据库中,从而创建重复条目。不仅如此,还会创建一个新的RelayConfig对象(我不知道在哪里)并将其插入到RelayConfigs表中。我实际上无法理解实体框架与多对多关系的工作方式。
@Ladislav,如果你有一些适用于多对多关系更新(对于分离的实体)的示例代码,那么我可以请求你请让我看到同样的内容。
问候, NIRVAN
EDIT3(解决方案):
最后,我结束了使用完全不同的方法。这里是更新的代码
public void Update(RelayConfig relayConfig, List<StandardContact> exposedContacts) {
context.Entry(relayConfig).State = EntityState.Modified;
relayConfig.StandardContacts.Clear();
exposedContacts.ForEach(exposedContact => {
StandardContact exposedContactEntity = null;
exposedContactEntity = context.StandardContacts.SingleOrDefault(sc => sc.Id == exposedContact.Id);
if (exposedContactEntity != null) {
relayConfig.StandardContacts.Add(exposedContactEntity);
}
});
}
关于, Nirvan。
感谢您的回复。但我仍然有疑问。让我们假设没有addedRecords或deletedRecords。假设一个RelayConfig有两个StandardContact记录,并且我想将这些更改保存到这两个StandardContact记录中,除了将它们的EntityState更改为已修改之外,是否还必须更改这两个StandardContacts的RelationshipState?我的意思是我们如何更新关系的多方面(忽略现在添加和删除的记录)。 – Jatin 2012-04-23 11:10:04
如果添加realayConfig,则必须将关系状态更改为未更改。如果你只是Attache realayConfig,你不必对这些关系做任何事情,但当你想添加新的关系时,附加可能会导致另一个问题。 – 2012-04-23 11:14:17
请看我的编辑标记为Edit2: – Jatin 2012-04-24 05:22:13