Skip to content

Unfulfillable nullable contraints are set for complex types with TPH entities #33004

@Wasserwecken

Description

@Wasserwecken

Usually, if a field has the Required attribute it is mapped as nullable: false.
But if this field is declared in a TPH entity, that condition may not be possible.

Unfortunately, required-flaged fields within complex types are set as NOT NULL anyway,
which prevents persisting entities that do not implement those fields.

image

Core for reproduction

Migrations are required (Add-Migration Init -c CustomContext5)

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ConsoleApp5
{
    internal static class Program5
    {
        public static void Test(string[] args)
        {
            var supplier = new Supplier() { Name = "Supplier", Extra = new() { Field = "Field" } };
            var customer = new Customer() { Name = "Customer" };

            using (var ctx = new CustomContext5())
            {
                ctx.Database.Migrate();
                ctx.Add(supplier);
                ctx.SaveChanges();

                ctx.Add(customer);
                ctx.SaveChanges();
            }

            Console.WriteLine("Done!");
            Console.ReadLine();
        }

        public class CustomContext5 : DbContext
        {
            public DbSet<Contact> Contacts { get; set; }
            public DbSet<Supplier> Suppliers { get; set; }
            public DbSet<Customer> Customers { get; set; }

            protected override void OnConfiguring(DbContextOptionsBuilder builder)
            {
                builder.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuting }).EnableSensitiveDataLogging();
                builder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=TestDb;Trusted_Connection=True");
            }

            protected override void OnModelCreating(ModelBuilder builder)
            {
                builder.Entity<Contact>().HasDiscriminator(e => e.Discriminator);
            }
        }

        public abstract class Contact
        {
            public int Id { get; set; }
            public string? Discriminator { get; set; }
            public string? Name { get; set; }
        }

        public class Supplier : Contact
        {
            [Required]
            public string? AnotherExtra { get; set; }
            public required Extra Extra { get; set; }
        }

        public class Customer : Contact
        {
        }

        [ComplexType]
        public class Extra
        {
            [Required]
            public string? Field { get; set; }
        }
    }
}

Include provider and version information

EF Core version: 8.0.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions