-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
dnx ef dbcontext scaffold generates improper WithMany definitions on related model? #4298
Comments
Because they are three separate relationships, so they can't share a navigation property. They all point to the same primary key, but they must be represented by three different foreign key columns in the database. I wonder if we could do something better with collection navigation property names by using the foreign key name - like we do for the reference navigation property (something like Out of interest, could you share the database schema for User and Book. |
ah that makes sense, thanks! but yeah, It would be super cool if the navigation property could be named after the foreign key somehow. Here are the relevant portions of the schema: modelBuilder.Entity<User>(entity =>
{
entity.ToTable("User");
...
// column definition stuff, no relationships
});
modelBuilder.Entity<Book>(entity =>
{
entity.ToTable("Book");
...
// column definition stuff, other relationships omitted
entity.HasOne(d => d.UserId_CreatedByNavigation).WithMany(p => p.Book1).HasForeignKey(d => d.UserId_CreatedBy).OnDelete(DeleteBehavior.Restrict);
entity.HasOne(d => d.UserId_ModifiedByNavigation).WithMany(p => p.BookNavigation).HasForeignKey(d => d.UserId_ModifiedBy).OnDelete(DeleteBehavior.Restrict);
entity.HasOne(d => d.UserId_OwnerNavigation).WithMany(p => p.Book).HasForeignKey(d => d.UserId_Owner).OnDelete(DeleteBehavior.Restrict);
}); |
@NullVoxPopuli any chance you could share the SQL definition for the tables. I can fairly confidently infer what it is based on the code that was generated... but it's always great to get actual real-world schemas to test against. |
Notes for triage: Given the following schema: CREATE TABLE [dbo].[Book](
[BookId] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] [nvarchar](max) NULL,
[CreatedByUserId] [int] NULL,
[ModifiedByUserId] [int] NULL,
[OwnerUserId] [int] NULL)
GO
CREATE TABLE [dbo].[User](
[UserId] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] [nvarchar](max) NULL)
GO
ALTER TABLE [dbo].[Book] WITH CHECK ADD CONSTRAINT [FK_Book_User_CreatedByUserId] FOREIGN KEY([CreatedByUserId])
REFERENCES [dbo].[User] ([UserId])
GO
ALTER TABLE [dbo].[Book] WITH CHECK ADD CONSTRAINT [FK_Book_User_ModifiedByUserId] FOREIGN KEY([ModifiedByUserId])
REFERENCES [dbo].[User] ([UserId])
GO
ALTER TABLE [dbo].[Book] WITH CHECK ADD CONSTRAINT [FK_Book_User_OwnerUserId] FOREIGN KEY([OwnerUserId])
REFERENCES [dbo].[User] ([UserId])
GO The properties on the dependent class look good (I reordered the generated properties for the sake of readability): public int? CreatedByUserId { get; set; }
public virtual User CreatedByUser { get; set; }
public int? ModifiedByUserId { get; set; }
public virtual User ModifiedByUser { get; set; }
public int? OwnerUserId { get; set; }
public virtual User OwnerUser { get; set; } But properties on the principal are pretty ugly (no way to tell what lines up with what unless you look at the model configuration): public virtual ICollection<Book> Book { get; set; }
public virtual ICollection<Book> BookNavigation { get; set; }
public virtual ICollection<Book> Book1 { get; set; } My proposal is that if there are multiple navigation to the same entity, then we use the FK column name in the nav prop name too (same as we do for the dependent end). A simple rule that should give something fairly clear in most cases would be <dependent_type_name><dependent_nav_prop_name>. We already have some logic to tidy up the name of the dependent property (removing public virtual ICollection<Book> BookModifiedByUser { get; set; }
public virtual ICollection<Book> BookCreatedByUser { get; set; }
public virtual ICollection<Book> BookOwnerUser { get; set; } |
@lajones the work item is just to implement the change mentioned in the comment above |
Note: Given the more usual set-up of only 1 FK between the 2 tables -
which is a bit weird. So we decided to only implement the above rules if there is more than 1 FK between the 2 tables. |
Checked in with commit d6abe4a. |
Is there a way I can test this out before waiting for a new release? like, in a Gemfile, you'd specify: gem 'fictional-entity-framework', github: 'aspnet/EntityFramework', branch: 'dev' to use the latest commit on that branch |
@NullVoxPopuli we have "nightly" builds (http://myget.org/F/aspnetvnext)... but they are a mess at the moment due to everyone moving over to .NET CLI. So I would hold off for a while until trying to use them. |
I generated my context and models from this command:
Which generated these
onModelCreating
definitions for myBook
Model.So, in the database, all 3 of those are configured the same,
on the
Book
table, the foreign keys,UserId_CreatedBy
,UserId_ModifiedBy
andUserId_Owner
all point to theUser
table'sUserId
column.I assume that the
UserId_CreatedByNavigation
,UserId_ModifiedByNavigation
andUserId_OwnerNavigation
are things used by entity framework?So,
where does
Book1
, andBookNavigation
come from? Why aren't all theWithMany
lambdas the same?The text was updated successfully, but these errors were encountered: