簡體   English   中英

實體框架6->外部服務->自引用外鍵-> INSERT語句與FOREIGN KEY約束沖突

[英]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集合並添加關系,或者實體框架可以以某種方式解決此問題?

我最終使用帶有自定義IEqualityComparerHashSet來避免TPRelatedCase任何重復。 我不得不從改變ICollection<TPRelatedCase> RelatedCasesIList<TPRelatedCase> RelatedCasesTPCase使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM