We are writing an application for an external service that feeds us data like this:
{"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,"…
Entity framework classes:
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; }
}
The data feed and classes are slimmed down to focus on the problem at hand. When I try to add any of these cases I get the following error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.TPRelatedCases_dbo.TPCases_RelatedBusinessSystemId_RelatedCaseId". The conflict occurred in database "Test.Database", table "dbo.TPCases".
The statement has been terminated.
This is of course understandable given our model but it means I cannot use the normal dbContext.Cases.Add(newCase);
for any of the objects above. Normally I can loop through the RelatedCases
collection recursively and add the foreign keys first but in this case it leads to an infinite loop
. Do I need to empty the TPCase.RelatedCases
collection and add relationships after the cases has been added or can entity framework solve this somehow?
I ended up using a HashSet
with a custom IEqualityComparer
to avoid any duplicates for TPRelatedCase
. I had to change from ICollection<TPRelatedCase> RelatedCases
to IList<TPRelatedCase> RelatedCases
in TPCase
to use the indexer
(array square bracket operator).
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();
}
}
Method to get new information and add RelatedCases in a later stage ( 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);
}
}
Recursive method to add all cases but no 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;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.