Skip to content
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

Support IDictionary navigation property for one-to-many relationship #21262

Open
Tracked by #240
kskalski opened this issue Jun 15, 2020 · 3 comments
Open
Tracked by #240

Support IDictionary navigation property for one-to-many relationship #21262

kskalski opened this issue Jun 15, 2020 · 3 comments

Comments

@kskalski
Copy link

My model uses field Children being (subtype of) IDictionary<child_key, Child> to express one-to-many relationship Parent-Child and supporting easy/fast access to children items.
I would like EF Core to support this pattern in similar way ICollection<Child> Children is handled.

Consider

  class Child {
    public long id { get; set; }
    public string Text { get; set; }
  }
  class Parent {
    public long id { get; set; }
    public string name { get; set; }
    public System.Collections.Generic.Dictionary<long, Child> Children { get; set; }
  }

this throws exception

Unhandled exception. System.InvalidOperationException: The property 'Parent.Children' is of type 'Dictionary<long, Child>' which is not supported by current database provid
er. Either change the property CLR type or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

and adding conversion specification like this:

      modelBuilder.Entity<Parent>()
       .Property(m => m.Children)
       .HasConversion(v => v.Values, v => v.ToDictionary(f => f.id, f => f));

doesn't help either.

I also found this question asking for similar feature with a number of hack solutions (https://stackoverflow.com/questions/60726966/ef-core-use-a-dictionary-property), none of them is really addressing the problem though.

When the property is (sub)type of ICollection<Child>, then it's treated as navigational property, with migrations it creates ParentId property in Child table, etc. With IDictionary and appropriate information about keys it could work in similar way and even keep better performance for some tracking operations.

@ajcvickers
Copy link
Contributor

@kskalski This is an interesting idea. Issue #752 is tracking custom collection mapping, but this is somewhat more than that because it would require EF to use the dictionary for internal look-ups on the collection,

@kskalski
Copy link
Author

While modelling similar relationship using existing capabilities I realized some difficulties of using IDictionary - namely the semantics of keys and operations related to adding the hierarchy to EF.

The key of dictionary might be used in two ways:

  1. when it's a (global) primary key of the Child entity, then it seems kind of easy and understandable for users of this data, however there is a bit painful limitation when adding a parent with a set of new children.
    [Currently EF supports adding multiple related entities at the same time, e.g. new A entity and several B entities stored in A's ICollection<B> navigational property, EF will take care of assigning new primary keys to both A and all Bs and the (generated by DB) ids are not affecting the structure / navigational properties.]
    When primary key of Child is to be generated by DB during addition, it's not clear how to create IDictionary with a bunch of them before they are added to DB, multiple Saves are required to do it properly. When I had such problem in my APIs I used some hacks, like assigning fake ids from invalid key domain (e.g. negative numbers).

  2. For my data model, I would rather use an IDictionary key that is relative to the Parent (so not a global primary key, but local key in scope of that single parent). In that case Child could have a separate global primary key (Id) and also a "relative key" field (e.g. Name) used as key in IDictionary.
    This approach solves the problem of adding the whole hierarchy of entities at once, provides a possibly more convenient model of using "scoped key", but I guess it requires a richer API and support from EF to specify foreign keys for IDictionary mapping properly.

Both 1. and 2. also require a ParentId field, but in case of 2. it's optionally possible to drop Child's Id field in favor of composite primary key (ParentId, Name), though it has kind of a "scaling" problem (imagine a deeper hierarchy with GrandChild and GrandGrandChild, they would require addressing all the ancestors' keys in their primary key).

@AndriySvyryd
Copy link
Member

This is a specific case of #2919

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

No branches or pull requests

3 participants