You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While it is currently possible to put foreign keys + navigation properties from owned types to other entities, it is not possible to have a navigation property from the target entity back to the owned type or parent entity. In the example below: It does not seem to be possible to add a collection to TeamMember which allows loading the UserStory items it is used.
We are in the need of bi-directional properties, but want to use owned types to reuse a commonly used set of navigation properties. e.g. in our real world use case we have multiple WorkItemAssignees in the UserStory, WorkItemAssignees also in other entities like Bug and also the WorkItemAssignees is pointing to multiple TeamMembers like Owner, Tester, Developer,...
If we flatten the owned type, bidirectional properties are possible.
Considering that the owned types are part of the parent entity, we think Attempt 3 should be a possible option to have from the TeamMember a navigation property to the UserStory because WorkItemAssignments cannot exist on their own. But also Attempt 5 would work fine.
Include your code
using Microsoft.EntityFrameworkCore;varoptionsBuilder=newDbContextOptionsBuilder<ScrumDbContext>().UseInMemoryDatabase("Test");awaitusingvardbContext=new ScrumDbContext(optionsBuilder.Options);
Console.WriteLine("Creating user");vardaniel= dbContext.Set<TeamMember>().Add(new TeamMember
{Name="Daniel"}).Entity;
Console.WriteLine("Creating story");
dbContext.Set<UserStory>().Add(new UserStory
{Title="US01",Assignees={Owner=daniel}});
Console.WriteLine("saving");await dbContext.SaveChangesAsync();
Console.WriteLine("saved");varallStoriesWithUsers=await
dbContext.Set<UserStory>().Include(u => u.Assignees.Owner).ToArrayAsync();foreach(var story in allStoriesWithUsers){
Console.WriteLine($"Story: {story.Id}{story.Title}");
Console.WriteLine($" Owner: {story.Assignees.Owner.Name}");}varusersWithStories=await dbContext
.Set<TeamMember>().Include(t => t.UserStoriesWhereOwner).ToArrayAsync();foreach(var user in usersWithStories){
Console.WriteLine($"User: {user.Id}{user.Name}");foreach(var story in user.UserStoriesWhereOwner){
Console.WriteLine($" Story: {story.Title}");}}classUserStory{publicintId{get;set;}publicstringTitle{get;set;}publicWorkItemAssigneesAssignees{get;set;}=new();}classWorkItemAssignees{publicUserStoryUserStory{get;set;}publicintOwnerId{get;set;}publicTeamMemberOwner{get;set;}}classTeamMember{publicintId{get;set;}publicstringName{get;set;}publicIList<UserStory> UserStoriesWhereOwner {get;set;}publicIList<WorkItemAssignees> AssigneesWhereOwner {get;set;}}classScrumDbContext:DbContext{publicScrumDbContext(DbContextOptions<ScrumDbContext>options):base(options){}protectedoverridevoidOnModelCreating(ModelBuildermodelBuilder){
modelBuilder.Entity<TeamMember>(e =>{ e.HasKey(x => x.Id); e.Property(x => x.Id).ValueGeneratedOnAdd();// Attempt 1: Unhandled exception. System.ArgumentException: The expression 'x => x.Assignees.Owner' is not a valid member access expression. The expression should represent a simple property or field access: 't => t.MyProperty'. (Parameter 'memberAccessExpression')// e.HasMany(x => x.UserStoriesWhereOwner)// .WithOne(x => x.Assignees.Owner)// .HasForeignKey(x => x.Assignees.OwnerId);// Attempt 2: Unhandled exception. System.ArgumentException: The expression 'x => Convert(x.Assignees.OwnerId, Object)' is not a valid member access expression. The expression should represent a simple property or field access: 't => t.MyProperty'. When specifying multiple properties or fields, use an anonymous type: 't => new { t.MyProperty, t.MyField }'. (Parameter 'memberAccessExpression')// e.HasMany(x => x.UserStoriesWhereOwner)// .WithOne()// .HasForeignKey(x => x.Assignees.OwnerId);});
modelBuilder.Entity<UserStory>(e =>{ e.HasKey(x => x.Id); e.Property(x => x.Id).ValueGeneratedOnAdd(); e.OwnsOne(x => x.Assignees,o =>{ o.WithOwner(x => x.UserStory); o.HasOne(x => x.Owner)// Attempt 3: compile error because expects IEnumerable<WorkItemAssignees>// .WithMany(x => x.UserStoriesWhereOwner)// Attempt 4: Unhandled exception. System.InvalidOperationException: The collection navigation 'UserStoriesWhereOwner' cannot be added to the entity type 'TeamMember' because its CLR type 'IList<UserStory>' does not implement 'IEnumerable<WorkItemAssignees>'. Collection navigations must implement IEnumerable<> of the related entity.// .WithMany(nameof(TeamMember.UserStoriesWhereOwner))// Attempt 5: Compiles but: Unhandled exception. System.InvalidOperationException: The navigation 'TeamMember.AssigneesWhereOwner' is not supported because it is pointing to an owned entity type 'WorkItemAssignees'. Only the ownership navigation from the entity type 'UserStory' can point to the owned entity type. See https://aka.ms/efcore-docs-owned for more information.// .WithMany(x => x.AssigneesWhereOwner)// Can run, but UserStoriesWhereOwner is not linked.WithMany().HasForeignKey(x => x.OwnerId);});});}}
Include stack traces
If relevant I can provide stack-traces for all error examples above, but I think it would bloat this issue. It rather seems an active limitation/restriction which is not documented but still enforced.
Include provider and version information
EF Core version: 6.0.9, 7.0.0-preview.7.22376.2
Database provider: Microsoft.EntityFrameworkCore.SqlServer and Microsoft.EntityFrameworkCore.InMemory
Target framework: .net 6.0
Operating system: Microsoft Windows 11 Enterprise 21H2
IDE: dotnet run
The text was updated successfully, but these errors were encountered:
File a bug
While it is currently possible to put foreign keys + navigation properties from owned types to other entities, it is not possible to have a navigation property from the target entity back to the owned type or parent entity. In the example below: It does not seem to be possible to add a collection to
TeamMember
which allows loading theUserStory
items it is used.We are in the need of bi-directional properties, but want to use owned types to reuse a commonly used set of navigation properties. e.g. in our real world use case we have multiple
WorkItemAssignees
in theUserStory
,WorkItemAssignees
also in other entities likeBug
and also theWorkItemAssignees
is pointing to multipleTeamMember
s like Owner, Tester, Developer,...If we flatten the owned type, bidirectional properties are possible.
Considering that the owned types are part of the parent entity, we think
Attempt 3
should be a possible option to have from theTeamMember
a navigation property to theUserStory
becauseWorkItemAssignments
cannot exist on their own. But alsoAttempt 5
would work fine.Include your code
Include stack traces
If relevant I can provide stack-traces for all error examples above, but I think it would bloat this issue. It rather seems an active limitation/restriction which is not documented but still enforced.
Include provider and version information
EF Core version: 6.0.9, 7.0.0-preview.7.22376.2
Database provider: Microsoft.EntityFrameworkCore.SqlServer and Microsoft.EntityFrameworkCore.InMemory
Target framework: .net 6.0
Operating system: Microsoft Windows 11 Enterprise 21H2
IDE:
dotnet run
The text was updated successfully, but these errors were encountered: