Skip to content

Self-referencing Many-to-many #915

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rachael-ross opened this issue Jan 5, 2021 · 2 comments
Closed

Self-referencing Many-to-many #915

rachael-ross opened this issue Jan 5, 2021 · 2 comments

Comments

@rachael-ross
Copy link

rachael-ross commented Jan 5, 2021

DESCRIPTION

I have an entity that can have other entities of the same type (Org) as "Clients" and "Parents" (parents can change over time) and an explicit relationship entity (OrgClient). Since the relationship entity has two properties of the same type (Org), JADNC can't, of course, automatically extrapolate the proper property it needs to create the relationship on.

STEPS TO REPRODUCE

 public class Org : Identifiable<long>
    {             
        [NotMapped]
        [HasManyThrough(nameof(OrgClients), InverseNavigation = "ClientOrg")]
        public ICollection<Org> Clients { get; set; } = new HashSet<Org>();

        [NotMapped]
        [HasManyThrough(nameof(ManagingOrgClients), InverseNavigation = "ManagingOrg")]
        public ICollection<Org> ManagingOrgs { get; set; } = new HashSet<Org>();

        public ICollection<OrgClient> OrgClients { get; set; } = new HashSet<OrgClient>();

        public ICollection<OrgClient> ManagingOrgClients { get; set; } = new HashSet<OrgClient>();
  
    }
public class OrgClient : Identifiable<long>
    {
        [Attr]
        public long ClientOrgId { get; set; }
        [HasOne]
        public virtual Org ClientOrg { get; set; }
        [Attr]
        public long ManagingOrgId { get; set; }
        [HasOne]
        public virtual Org ManagingOrg { get; set; }       
    }
 public void Configure(EntityTypeBuilder<OrgClient> builder)
        {
            builder.HasKey(e => e.Id);            
           
            builder.HasOne(e => e.ClientOrg).WithMany(d => d.OrgClients).HasForeignKey(d => d.ManagingOrgId).IsRequired().OnDelete(DeleteBehavior.NoAction);
            builder.HasOne(e => e.ManagingOrg).WithMany(d => d.ManagingOrgClients).HasForeignKey(d => d.ClientOrgId).IsRequired().OnDelete(DeleteBehavior.NoAction);
        }

EXPECTED BEHAVIOR

I thought specifying the InverseNavigation property would take care of that, but it appears that value is being ignored when building the relationships.

ACTUAL BEHAVIOR

I was experiencing an exception being thrown in ResourceGraphBuilder::GetRelationships() on this line:

hasManyThroughAttribute.LeftProperty = throughProperties.SingleOrDefault(x => x.PropertyType.IsAssignableFrom(resourceType))
                            ?? throw new InvalidConfigurationException($"{throughType} does not contain a navigation property to type {resourceType}");

Since OrgClient has two properties of the same type (Org), the SingleOrDefault is choking.

Locally, I've added logic to examine the InverseNavigation property of the HasManyThroughAttribute, if it's been assigned, and it seems all is working fine with that, but I've not made it through tests for all CRUD operations yet. I'm not sure if there are further considerations I need to make for this, if this is a bug, a feature request or I'm just simply missing something?

VERSIONS USED

  • JsonApiDotNetCore version: master as of 11/15/2020
  • ASP.NET Core version: 3.1
  • Entity Framework Core version: 3.1.10
  • Database provider: Sql Server
@bart-degreed
Copy link
Contributor

This sounds like a duplicate of #790, which is solved by setting LeftPropertyName/RightPropertyName. See our tests for details. Does that help?

@rachael-ross
Copy link
Author

Yep, that's it. Your fix is very similiar to what I did, but just wanted to report it. Didn't realize someone already had. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants