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

Only the 1st Owned Entity property can be configured by Fluent API #14096

Closed
ganaware opened this Issue Dec 6, 2018 · 2 comments

Comments

Projects
None yet
3 participants
@ganaware

ganaware commented Dec 6, 2018

Only the 1st Owned Entity property can be configured by Fluent API

Steps to reproduce

A complete project is here: https://github.com/ganaware/TestEFCoreOwned

I defined an entity Book that has three Owned Entity properties: EnglishInfo, JapaneseInfo and ChineseInfo.
The type of these properties is Info configured by fluend API.

    public class Book {
        public int BookId { get; set; }
        public Info EnglishInfo { get; set; }
        public Info JapaneseInfo { get; set; }
        public Info ChineseInfo { get; set; }

        public static void OnModelCreating(ModelBuilder modelBuilder) {
            var e_tb = modelBuilder.Entity<Book>();
            e_tb.Property(e => e.BookId);
            e_tb.OwnsOne(e => e.EnglishInfo);
            e_tb.OwnsOne(e => e.JapaneseInfo);
            e_tb.OwnsOne(e => e.ChineseInfo);
        }
    }

    public class Info {
        public string Title { get; set; } // a general column
        public string Author { get; set; } // a column specified HasMaxLength() by fluent API
        string Memo { get; set; } // with fluent API, a column can be implemented by a private property

        public static void OnModelCreating(ModelBuilder modelBuilder) {
            EntityTypeBuilder<Info> e_tb = modelBuilder.Entity<Info>();
            e_tb.Property(e => e.Title);
            e_tb.Property(e => e.Author)
                .HasMaxLength(100);
            e_tb.Property(e => e.Memo);
        }
    }

    public class MyContext : DbContext {
        public DbSet<Book> Books { get; set; }

        public MyContext() {
        }

        public MyContext(DbContextOptions<MyContext> options)
            : base(options) {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
            if (!optionsBuilder.IsConfigured) {
                optionsBuilder.UseSqlite(new SqliteConnection("DataSource=:memory:"));
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            base.OnModelCreating(modelBuilder);
            Info.OnModelCreating(modelBuilder);
            Book.OnModelCreating(modelBuilder);
        }
    }

    public class MyContextForMigrationFactory : IDesignTimeDbContextFactory<MyContext> {
        public MyContext CreateDbContext(string[] args) {
            return new MyContext();
        }
    }

Then, I created a migration by dotnet command:

dotnet ef migrations add InitialCreate

The generated 20181206004616_InitialCreate.cs is:

    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Books",
                columns: table => new
                {
                    BookId = table.Column<int>(nullable: false)
                        .Annotation("Sqlite:Autoincrement", true),
                    EnglishInfo_Title = table.Column<string>(nullable: true),
                    EnglishInfo_Author = table.Column<string>(maxLength: 100, nullable: true),
                    EnglishInfo_Memo = table.Column<string>(nullable: true),
                    JapaneseInfo_Title = table.Column<string>(nullable: true),
                    JapaneseInfo_Author = table.Column<string>(nullable: true),
                    ChineseInfo_Title = table.Column<string>(nullable: true),
                    ChineseInfo_Author = table.Column<string>(nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Books", x => x.BookId);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Books");
        }
    }

The problem is:

  • JapaneseInfo_Author has no maxLength.
  • JapaneseInfo_Memo is missing.
  • ChineseInfo_Author has no maxLength.
  • ChineseInfo_Memo is missing.

In short, Only the 1st Owned Entity property (EnglishInfo) can be configured by Fluent API. Configurations for 2nd (JapaneseInfo) and 3rd (ChineseInfo) are ignored.

Further technical details

  • EF Core version: 2.1.4, 2.2.0
  • Database Provider: Microsoft.EntityFrameworkCore.Sqlite 2.2.0, Pomelo.EntityFrameworkCore.MySql 2.1.4
  • Operationg system: Windows 7
  • IDE: Visual Studio 2017 15.8.7
@smitpatel

This comment has been minimized.

Contributor

smitpatel commented Dec 6, 2018

Duplicate of #9148

@smitpatel smitpatel marked this as a duplicate of #9148 Dec 6, 2018

@ganaware

This comment has been minimized.

ganaware commented Dec 6, 2018

Thank you. I understand that it's my bug.

I fixed as follows:

    public class Book {
        ...
        public static void OnModelCreating(ModelBuilder modelBuilder) {
            var e_tb = modelBuilder.Entity<Book>();
            e_tb.Property(e => e.BookId);
            e_tb.OwnsOne(e => e.EnglishInfo, cb => Info.OnModelCreating(cb));
            e_tb.OwnsOne(e => e.JapaneseInfo, cb => Info.OnModelCreating(cb));
            e_tb.OwnsOne(e => e.ChineseInfo, cb => Info.OnModelCreating(cb));
        }
    }

    public class Info {
        ...
        public static void OnModelCreating<T>(ReferenceOwnershipBuilder<T, Info> rob) where T : class {
            rob.Property(e => e.Title);
            rob.Property(e => e.Author)
                .HasMaxLength(100);
            rob.Property(e => e.Memo);
        }
    }

    public class MyContext : DbContext {
        ...
        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            base.OnModelCreating(modelBuilder);
            //Info.OnModelCreating(modelBuilder);
            Book.OnModelCreating(modelBuilder);
        }
    }

Everything works as expected.

Fixed project is here: https://github.com/ganaware/TestEFCoreOwned/tree/ProblemSolved

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