#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()));