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

Problem with inherited owned type #20220

Closed
lenraven opened this issue Mar 8, 2020 · 7 comments · Fixed by #29042
Closed

Problem with inherited owned type #20220

lenraven opened this issue Mar 8, 2020 · 7 comments · Fixed by #29042
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported punted-for-5.0 punted-for-6.0 type-bug
Milestone

Comments

@lenraven
Copy link

lenraven commented Mar 8, 2020

I have a problem with mapping of a complex domain model.
The problem is the generated mapping of Owned type.
When I created a migration step, then there will be two compiler error in the code.

Model what I want to map

    public class Entity
    {
        public int Id { get; set; }
        public BookingInterval Interval { get; set; }
        public DateRange Range { get; set; }
    }

    public class DateRange
    {
        public DateTime From { get; set; }
        public DateTime To { get; set; }
    }

    public class BookingInterval : DateRange
    {
        public DateTime CheckIn { get; set; }
        public DateTime CheckOut { get; set; }
    }

The Context file with mapping

    public class POCContext : DbContext
    {
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            var entityBuilder = modelBuilder.Entity<Entity>();
            entityBuilder.OwnsOne(p => p.Interval, ob =>
            {
                ob.Property(p => p.CheckIn).IsRequired();
                ob.Property(p => p.CheckOut).IsRequired();
                ob.Ignore(p => p.From);
                ob.Ignore(p => p.To);
            });
            entityBuilder.Ignore(p => p.Range);
            modelBuilder.Ignore<DateRange>();
            base.OnModelCreating(modelBuilder);
        }
    }

The problem

When I call the Add-Migration command, then the following Snapshot will be generated.

    [DbContext(typeof(POCContext))]
    partial class POCContextModelSnapshot : ModelSnapshot
    {
        protected override void BuildModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder
                .HasAnnotation("ProductVersion", "3.1.2")
                .HasAnnotation("Relational:MaxIdentifierLength", 128)
                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

            modelBuilder.Entity("EFCoreMigrationProblem1.Model.Entity", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("int")
                        .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

                    b.HasKey("Id");

                    b.ToTable("Entity");
                });

            modelBuilder.Entity("EFCoreMigrationProblem1.Model.Entity", b =>
                {
                    b.OwnsOne("EFCoreMigrationProblem1.Model.BookingInterval", "Interval", b1 =>
                        {
                            b1.Property<int>("EntityId")
                                .ValueGeneratedOnAdd()
                                .HasColumnType("int")
                                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

                            b1.Property<DateTime>("CheckIn")
                                .HasColumnType("datetime2");

                            b1.Property<DateTime>("CheckOut")
                                .HasColumnType("datetime2");

                            b1.HasKey("EntityId");

                            b1.ToTable("Entity");

                            // The problem is here!
                            b1.HasDiscriminator();

                            b1.WithOwner()
                                .HasForeignKey("EntityId");
                        });
                });
#pragma warning restore 612, 618
        }
    }

So the problem is that, the b1.HasDiscriminator(); method case compiler error.
And same problem is in Designer file of migration step.

Workaround

I found a workaround to this problem, but it is not fitting well with my domain model.
The model of workaround:

    public class Entity
    {
        public int Id { get; set; }
        public BookingInterval Interval { get; set; }
        public DateRange Range { get; set; }
    }
    public class DateRangeBase
    {
        public DateTime From { get; set; }
        public DateTime To { get; set; }
    }
    public class DateRange : DateRangeBase
    {
        public DateTime From { get; set; }
        public DateTime To { get; set; }
    }
    public class BookingInterval : DateRangeBase
    {
        public DateTime CheckIn { get; set; }
        public DateTime CheckOut { get; set; }
    }

Further technical details

EF Core version: 3.1.2
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: All traget
Operating system: Windows 10
IDE: Visual Studio 2019 16.4.5

@ajcvickers
Copy link
Member

@lenraven Just to clarify, based on your OnModelCreating code, you want Entity.Interval to reference an owned type, and Entity.Range to not be mapped at all. Is that correct?

@ajcvickers
Copy link
Member

Note for team: This still repros even when both types are mapped as owned entities and nothing is ignored in the model.

@lenraven
Copy link
Author

lenraven commented Mar 9, 2020

@ajcvickers Yes, the mapping, what I created, do it.

But I checked it again, and the problem will be occurred, only when the DateRange, and the BookingInterval are on same Entity and not depends on it is ignored or not.

The following model will NOT occur the problem:

    public class Entity1
    {
        public int Id { get; set; }
        public BookingInterval Interval { get; set; }
    }

    public class Entity2
    {
        public int Id { get; set; }
        public DateRange Range { get; set; }
    }

    public class POCContext : DbContext
    {
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            var entityBuilder1 = modelBuilder.Entity<Entity1>();
            entityBuilder1.OwnsOne(p => p.Interval, ob =>
            {
                ob.Property(p => p.CheckIn).IsRequired();
                ob.Property(p => p.CheckOut).IsRequired();
                ob.Ignore(p => p.From);
                ob.Ignore(p => p.To);
            });
           var entityBuilder2 = modelBuilder.Entity<Entity2>();
            entityBuilder2.OwnsOne(p => p.Range, ob =>
            {
                ob.Property(p => p.From).IsRequired();
                ob.Property(p => p.From).IsRequired();
            });
            base.OnModelCreating(modelBuilder);
        }
    }

@ajcvickers
Copy link
Member

@lenraven Thanks for the additional info.

@bricelam @AndriySvyryd Tried this on recent daily build and it now throws when adding the migration:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.EntityFrameworkCore.Design.Internal.CSharpHelper.Literal(String value)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityTypeAnnotations(String builderName, IEntityType entityType, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityType(String builderName, IEntityType entityType, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateOwnedType(String builderName, IForeignKey ownership, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateOwnedTypes(String builderName, IEnumerable`1 ownerships, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateRelationships(String builderName, IEntityType entityType, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityTypeRelationships(String builderName, IEntityType entityType, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityTypes(String builderName, IReadOnlyList`1 entityTypes, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.Generate(String builderName, IModel model, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGenerator.GenerateMetadata(String migrationNamespace, Type contextType, String migrationName, String migrationId, IModel targetModel)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

@AndriySvyryd AndriySvyryd self-assigned this Mar 9, 2020
@AndriySvyryd
Copy link
Member

@lenraven Try adding this line as a workaround:

            entityBuilder.OwnsOne(p => p.Interval, ob =>
            {
                ob.GetInfrastructure().HasNoDeclaredDiscriminator(ConfigurationSource.Explicit);
            });

@lenraven
Copy link
Author

@AndriySvyryd Unfortunately this solution did not solve the problem.

@AndriySvyryd
Copy link
Member

Possibly a symptom of #19311

@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Sep 10, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0, 7.0.0-rc2 Sep 12, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0-rc2, 7.0.0 Nov 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported punted-for-5.0 punted-for-6.0 type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants