![](/img/trans.png)
[英]Entity Framework code first INSERT statement conflicted with the FOREIGN KEY constraint
[英]Entity Framework 6 -> External Service -> self referencing foreign key -> The INSERT statement conflicted with the FOREIGN KEY constraint
我們正在為外部服務編寫一個應用程序,該應用程序向我們提供如下數據:
{"businessSystemId":"SE","caseId":1,…,"relatedCases":[{"businessSystemId":"SE","caseId":1,"relationshipNo":123,"relatedBusinessSystemId":"SE","relatedCaseId":2,"…
{"businessSystemId":"SE","caseId":2,…,"relatedCases":[{"businessSystemId":"SE","caseId":2,"relationshipNo":123,"relatedBusinessSystemId":"SE","relatedCaseId":1,"…
實體框架類:
public class TPCase
{
[Key, Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string BusinessSystemId { get; set; }
[Key, Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CaseId { get; set; }
public virtual ICollection<TPRelatedCase> RelatedCases { get; set; }
}
public class TPRelatedCase
{
[Key, Column(Order = 0)]
[ForeignKey("TPCase")]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string BusinessSystemId { get; set; }
[Key, Column(Order = 1)]
[ForeignKey("TPCase")]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CaseId { get; set; }
[InverseProperty("RelatedCases")]
public virtual TPCase TPCase { get; set; }
[Key, Column(Order = 2)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int RelationshipNo { get; set; }
[ForeignKey("RelatedCase"), Column(Order = 3)]
public string RelatedBusinessSystemId { get; set; }
[ForeignKey("RelatedCase"), Column(Order = 4)]
public int? RelatedCaseId { get; set; }
public virtual TPCase RelatedCase { get; set; }
}
精簡了數據提要和類,以專注於眼前的問題。 當我嘗試添加任何這些情況時,都會出現以下錯誤:
INSERT語句與FOREIGN KEY約束“ FK_dbo.TPRelatedCases_dbo.TPCases_RelatedBusinessSystemId_RelatedCaseId”沖突。 數據庫“ Test.Database”的表“ dbo.TPCases”中發生了沖突。
該語句已終止。
對於我們的模型,這當然是可以理解的,但是這意味着我不能使用常規的dbContext.Cases.Add(newCase);
對於上述任何對象。 通常,我可以遞歸地循環瀏覽RelatedCases
集合並首先添加外鍵,但在這種情況下,它將導致infinite loop
。 添加案例之后,我是否需要清空TPCase.RelatedCases
集合並添加關系,或者實體框架可以以某種方式解決此問題?
我最終使用帶有自定義IEqualityComparer
的HashSet
來避免TPRelatedCase
任何重復。 我不得不從改變ICollection<TPRelatedCase> RelatedCases
到IList<TPRelatedCase> RelatedCases
在TPCase
使用indexer
(陣列方括號操作符)。
IEqualityComparer:
public class TPRelatedCaseComparer : IEqualityComparer<TPRelatedCase>
{
public bool Equals(TPRelatedCase x, TPRelatedCase y)
{
var xJson = JsonConvert.SerializeObject(x);
var yJson = JsonConvert.SerializeObject(y);
return xJson.Equals(yJson);
}
public int GetHashCode(TPRelatedCase obj)
{
return obj.BusinessSystemId.GetHashCode() + obj.CaseId.GetHashCode() + obj.RelationshipNo.GetHashCode();
}
}
獲取新信息並在以后的階段中添加RelatedCases的方法( AddOrUpdateRelatedCases
):
public void AddOrUpdateNewInformation(InformationToGet info)
{
AddOrUpdatePossibleForeignKeys(info);
var comparer = new TPRelatedCaseComparer();
var relatedCases = new HashSet<TPRelatedCase>(comparer);
_logger.Info($"Started updating cases");
foreach (var infoCaseKey in info.CaseKeys)
{
var newCase = _integrationApiService.GetCase(infoCaseKey.BusinessSystemId, infoCaseKey.CaseId);
AddOrUpdateCase(newCase, relatedCases);
AddOrUpdateRelatedCases(relatedCases);
}
}
遞歸方法,用於添加所有案例,但不添加RelatedCases。
private HashSet<TPRelatedCase> AddOrUpdateCase(TPCase newCase, HashSet<TPRelatedCase> relatedCases)
{
if (newCase?.RelatedCases?.Count > 0)
{
relatedCases.UnionWith(newCase.RelatedCases);
foreach (var relatedCase in newCase.RelatedCases)
{
if (relatedCase.RelatedCaseId.HasValue)
{
var newRelatedCase = _integrationApiService.GetCase(relatedCase.RelatedBusinessSystemId, relatedCase.RelatedCaseId.Value);
for (int i = 0; i < newRelatedCase.RelatedCases.Count - 1; i++)
{
if (relatedCases.Any(x =>
x.BusinessSystemId == newRelatedCase.RelatedCases[i].BusinessSystemId && x.CaseId ==
newRelatedCase.RelatedCases[i].CaseId && x.RelationshipNo == newRelatedCase.RelatedCases[i].RelationshipNo))
{
newRelatedCase.RelatedCases.Remove(newRelatedCase.RelatedCases[i]);
}
}
relatedCases = AddOrUpdateCase(newRelatedCase, relatedCases);
}
}
}
//Need to clear RelatedCases due to the fact that circular references could happen and therefore a recursive method is not possible.
//Would lead to FOREIGN KEY constraint exception.
newCase.RelatedCases = null;
var current = _dbContext.Cases.Find(newCase.BusinessSystemId, newCase.CaseId);
if (current == null)
{
_dbContext.Cases.Add(newCase);
}
else
{
_dbContext.Entry(current).CurrentValues.SetValues(newCase);
}
_dbContext.SaveChanges();
return relatedCases;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.