Как запретить EF Core создавать объекты DDD ValueObjects в виде таблиц

#c# #entity-framework-core #.net-5

#c# #entity-framework-core #.net-5

Вопрос:

Я использую ядро EF 5.0.1

Я создал следующий объект значений

 public class Address : BaseValueObject
    {

        public Address(string street, string zipCode, string city, string state, string country)
        {
            Street = street;
            ZipCode = zipCode;
            City = city;
            State = state;
            Country = country;
        }

        public string Street { get; set;  }
        public string ZipCode { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Country { get; set; }
        
        protected override IEnumerable<object> GetEqualityComponents()
        {
            yield return Street;
            yield return ZipCode;
            yield return City;
            yield return State;
            yield return Country;
        }

    }
 

и объект, которому принадлежит объект значения

 public class Location : BaseEntity
    {
        [Required]        
        public string Name { get; set; }
        
        public Address Address { get; set; }
    }
 

Объект Location настроен следующим образом

 public class LocationConfiguration : BaseEntityConfiguration<Location>
    {
        public override void Configure(EntityTypeBuilder<Location> builder)
        {            
            builder.OwnsOne(o => o.Address, a =>
            {
                a.Property(p => p.Street).HasMaxLength(600)
                    .HasDefaultValue("");
                a.Property(p => p.City).HasMaxLength(150)
                    .HasDefaultValue("");
                a.Property(p => p.State).HasMaxLength(60)
                    .HasDefaultValue("");
                a.Property(p => p.ZipCode).HasMaxLength(12)
                    .HasDefaultValue("");
            });

            base.Configure(builder);
        }
    }
 

Проблема в том, что миграция ядра EF по-прежнему создает объекты значений в виде таблиц в базе данных.
Что я делаю не так?
В сгенерированном коде миграции я вижу следующее:

 migrationBuilder.CreateTable(
                name: "Location",
                columns: table => new
                {
                    Id = table.Column<long>(type: "INTEGER", nullable: false)
                        .Annotation("Sqlite:Autoincrement", true),
                    Name = table.Column<string>(type: "TEXT", maxLength: 80, nullable: false),
                    Timestamp = table.Column<string>(type: "TEXT", rowVersion: true, nullable: false, defaultValueSql: "CURRENT_TIMESTAMP")
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Location", x => x.Id);
                });



migrationBuilder.CreateTable(
                name: "Address",
                columns: table => new
                {
                    LocationId = table.Column<long>(type: "INTEGER", nullable: false),
                    Street = table.Column<string>(type: "TEXT", maxLength: 600, nullable: true, defaultValue: ""),
                    ZipCode = table.Column<string>(type: "TEXT", maxLength: 12, nullable: true, defaultValue: ""),
                    City = table.Column<string>(type: "TEXT", maxLength: 150, nullable: true, defaultValue: ""),
                    State = table.Column<string>(type: "TEXT", maxLength: 60, nullable: true, defaultValue: ""),
                    Country = table.Column<string>(type: "TEXT", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Address", x => x.LocationId);
                    table.ForeignKey(
                        name: "FK_Address_Location_LocationId",
                        column: x => x.LocationId,
                        principalTable: "Location",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                });
 

и, наконец, класс DbContext

 public class MyDbContext : DbContext
    {        
        public PlannerDbContext(DbContextOptions<PlannerDbContext> options)
            : base(options)
        {
        }                     
        
        public DbSet<Location> Locations { get; set; }        


        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {            
            // do not use plural form for table names
            modelBuilder.Model.GetEntityTypes()
                .Configure(e => e.SetTableName(e.DisplayName())); 
                            
            base.OnModelCreating(modelBuilder);                                              

            modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());            
        }
    }
 

Комментарии:

1. Для меня все выглядит нормально. Единственная странность заключается в том, что частный конструктор без параметров для объекта Address . Вы получите тот же результат, если удалите это?

2. И, не то чтобы это должно было иметь значение, статический метод Create возвращает результат<Address> вместо просто Address .

3. Как насчет использования fluentapi в OnModelCreating в dbcontext : modelBuilder.Entity<Location>().OwnsOne(c => c.Address, a =>{ //... });

4. И в вашем контексте удалите код public DbSet<Address> Address{ get; set; }

5. @Yinqiu В классе DbContext нет DbSet<Address> Address{ get; set; } . настройка конфигурации в OnModelCreating в dbcontext ничего не изменила

Ответ №1:

Причиной, по которой EF создавал таблицы для объектов значений, была часть кода, в которой изменено соглашение об именовании таблиц. Я думаю, я скопировал это из какого-то вопроса SO о том, как установить имена таблиц в единственном числе.

Этот метод modelBuilder.Model.GetEntityTypes() возвращает перечислитель для всех объектов из модели (включая объекты значений). Настройка свойства имени таблицы для объекта value приведет к тому, что EF будет рассматривать этот тип как сущность.

Эта часть

             // do not use plural form for table names
            modelBuilder.Model.GetEntityTypes()
                .Configure(e => e.SetTableName(e.DisplayName())); 
 

следует изменить на

             // do not use plural form for table names
            modelBuilder.Model.GetEntityTypes()
                .Where(x => !x.ClrType.IsSubclassOf(typeof(BaseValueObject)))
                .Configure(e => e.SetTableName(e.DisplayName()));