-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
This is one of the building blocks for many-to-many. However, it is also more broadly useful than just many-to-many.
Problem
Consider a model typical for a many-to-many relationship:
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
public DateTime LinkCreated { get; set; }
}Now consider how to load a Post and include all associated Tags. This requires using two navigation properties--one to go from Post to PostTag, and a second to go from PostTag to Post. For example:
var postsAndTags
= context.Posts
.Include(e => e.PostTags)
.ThenInclude(e => e.Tag)
.ToList();Likewise, querying across Posts and Tags also requires use of PostTags:
var post
= context.Posts
.Where(e => e.PostTags.Select(e => e.Tag.Content).Contains("MyTag")).ToList();Proposal
The goal of forwarded navigation properties is to allow navigation properties to be defined which forward to some of the direct navigation properties in the model.
For example, forwarded navigation properties could be added to Post and Tag in the model above:
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<Tag> Tags { get; set; } // Skips over PostTag to Tag
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public string Content { get; set; }
public List<Post> Posts { get; set; } // Skips over PostTag to Post
public List<PostTag> PostTags { get; set; }
}These forwarded navigation properties can then used to write simpler queries. For example, the queries from above can now be:
var postsAndTags
= context.Posts
.Include(e => e.Tags)
.ToList();var post
= context.Posts
.Where(e => e.Tags.Select(e => e.Content).Contains("MyTag")).ToList();Notes
Things to consider (non-exhaustive):
- Model building API will be needed for the general case
- Conventions/sugar may be use later for many-to-many pattern
- Configuration by attribute could be considered, but might be too complex
- It should be possible to define the skip-level navigation that skip over relationships that do not themselves expose navigation properties
- This could involve shadow navigation properties if needed
- However, also note that it is expected that "skipped" entity types (like for the join table in the example) can still be used explicitly as needed. This allows additional properties to be used, such as the LinkCreated property in the example above.
Tasks:
- Model support
- Fluent API
- Change tracking support
- Query support
- Tracking query tests