Skip to content

Commit

Permalink
Fixes #3114: Fix the StackOverflow exception when retrieve Partner on…
Browse files Browse the repository at this point in the history
… navigation property from big CSDL model
  • Loading branch information
xuzhg committed Nov 13, 2024
1 parent b84465b commit d6a6dc8
Show file tree
Hide file tree
Showing 4 changed files with 7,541 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ private IEdmEntityType ComputeTargetEntityType()
return (IEdmEntityType)target;
}

private IEdmNavigationProperty ComputePartner()
internal IEdmNavigationProperty ResolveParter()
{
var partnerPropertyPath = this.navigationProperty.PartnerPath;
IEdmEntityType targetEntityType = this.TargetEntityType;
Expand All @@ -177,16 +177,42 @@ private IEdmNavigationProperty ComputePartner()
?? new UnresolvedNavigationPropertyPath(targetEntityType, partnerPropertyPath.Path, Location);
}

return null;
}

private IEdmNavigationProperty ComputePartner()
{
// The old logic is that:
// If the navigation property has the partner path, use the path to resolve the partner.
// If the partner path is null or empty, search navigation properties on target entity type.
// If the partner on navigation property on target entity type is same as the current navigation property,
// returns the navigation property on target entity type as the partner for current navigation property.
// If the target entity type has many navigation properties, it will throw StackOverflow exception.
// Now, use a cache on the declaring type to hold the partners on all navigation properties.
// It only runs when retrieving the partners.
IDictionary<IEdmNavigationProperty, IEdmNavigationProperty> partners = declaringType.GetNavigationPartners();
if (partners.TryGetValue(this, out IEdmNavigationProperty partner))
{
return partner;
}

IEdmEntityType targetEntityType = this.TargetEntityType;
CsdlSemanticsStructuredTypeDefinition targetCsdlType = (CsdlSemanticsStructuredTypeDefinition)targetEntityType;
IDictionary<IEdmNavigationProperty, IEdmNavigationProperty> targetPartners = targetCsdlType.GetNavigationPartners();

foreach (IEdmNavigationProperty potentialPartner in targetEntityType.NavigationProperties())
{
if (potentialPartner == this)
{
continue;
}

if (potentialPartner.Partner == this)
if (targetPartners.TryGetValue(potentialPartner, out partner))
{
return potentialPartner;
if (partner == this)
{
return potentialPartner;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ internal abstract class CsdlSemanticsStructuredTypeDefinition : CsdlSemanticsTyp
private readonly Cache<CsdlSemanticsStructuredTypeDefinition, IDictionary<string, IEdmProperty>> propertiesDictionaryCache = new Cache<CsdlSemanticsStructuredTypeDefinition, IDictionary<string, IEdmProperty>>();
private static readonly Func<CsdlSemanticsStructuredTypeDefinition, IDictionary<string, IEdmProperty>> ComputePropertiesDictionaryFunc = (me) => me.ComputePropertiesDictionary();

// A cache to save the navigation property partners based on the navigation property partner path if and only if the path is not null/empty.
private IDictionary<IEdmNavigationProperty, IEdmNavigationProperty> navigationPartners;

protected CsdlSemanticsStructuredTypeDefinition(CsdlSemanticsSchema context, CsdlStructuredType type)
: base(type)
{
Expand Down Expand Up @@ -87,6 +90,26 @@ public IEdmProperty FindProperty(string name)
return result;
}

public IDictionary<IEdmNavigationProperty, IEdmNavigationProperty> GetNavigationPartners()
{
if (navigationPartners == null)
{
navigationPartners = new Dictionary<IEdmNavigationProperty, IEdmNavigationProperty>();

foreach (var navigationProperty in this.NavigationProperties())
{
var nav = (CsdlSemanticsNavigationProperty)navigationProperty;
IEdmNavigationProperty partner = nav.ResolveParter();
if (partner != null)
{
navigationPartners[navigationProperty] = partner;
}
}
}

return navigationPartners;
}

protected List<IEdmProperty> ComputeDeclaredProperties()
{
List<IEdmProperty> properties = new List<IEdmProperty>();
Expand Down
Loading

0 comments on commit d6a6dc8

Please sign in to comment.