我有一个实体Product和一个ValueObject Money。
public class Product
{
public Product() { }
[Key]
public int Id { get; set; }
public string Name { get; set; }
public Money Price { get; set; }
}
public class Money : BaseValueObject
{
public Money(string currency, decimal amount)
{
if (string.IsNullOrEmpty(currency))
throw new ArgumentNullException(nameof(currency));
this.Currency = currency;
this.Amount = amount;
}
public string Currency { get; private set; }
public decimal Amount { get; private set; }
protected override IEnumerable<object?> GetEqualityComponents()
{
yield return Currency;
yield return Amount;
}
}我以这种方式设置了一个表配置:
public class ProductEntityTypeConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.ToTable("Products");
builder.HasKey(product => product.Id);
builder.Property(product => product.Name)
.HasColumnName("Name");
builder.OwnsOne(product => product.Price,
navigationBuilder =>
{
navigationBuilder.Property(money => money.Amount)
.HasColumnName("Price");
navigationBuilder.Property(money => money.Currency)
.HasColumnName("Currency");
});
}
}
public class ProductContext : DbContext
{
public ProductContext(DbContextOptions<ProductContext> options) : base(options) { }
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new ProductEntityTypeConfiguration());
// seeding
modelBuilder.Entity<Product>(p =>
{
p.HasData(
new Product { Id = 1, Name = "cola" },
new Product { Id = 2, Name = "chips" },
new Product { Id = 3, Name = "candy" }
);
p.OwnsOne(p => p.Price).HasData(
new Money("EUR", 100),
new Money("EUR", 050),
new Money("EUR", 065)
);
});
}因为Money是一个valueObject,所以它没有键。我希望使用此配置存储在同一个Product中,而不是1个price字段,2个字段:一个名为"Price“,另一个称为”货币“。
配置运行正常,但是当“种子”执行时,我得到:
System.InvalidOperationException:“无法添加实体类型”Money“的种子实体,因为所需的属性”ProductId“没有提供任何价值。”
不明白为什么要ProductId。那么,什么是ValueObject种子的正确方式呢?
我使用的是.NET 6和EF核心6。
发布于 2022-02-04 11:00:46
对于用于跟踪的拥有实体类型,需要拥有类型的主键作为阴影属性创建。。拥有类型的实例的键的值将与所有者实例的键值相同。
可以使用匿名对象将它的值指定为种子数据:
modelBuilder.Entity<Product>(p =>
{
p.HasData(
new Product { Id = 1, Name = "cola" },
new Product { Id = 2, Name = "chips" },
new Product { Id = 3, Name = "candy" }
);
p.OwnsOne(pr => pr.Price)
.HasData(
new { ProductId = 1, Currency = "EUR", Amount = 100m },
new { ProductId = 2, Currency = "EUR", Amount = 050m },
new { ProductId = 3, Currency = "EUR", Amount = 065m }
);
});发布于 2022-11-05 08:57:05
作为另一种选择,您可以使用以下方法创建一个静态类:
public class ProductEntityTypeConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
// ...
builder.OwnsOne(product => product.Price,
navigationBuilder =>
{
// ...
DataSeeder.Seed(navigationBuilder)
});
DataSeeder.Seed(builder);
}
private class DataSeeder
{
private static readonly List<Product> Products = new()
{
new Product { Name = "cola", Price = { Currency = "EUR", Amount = 100m } },
new Product { Name = "chips", Price = { Currency = "EUR", Amount = 100m } },
new Product { Name = "candy", Price = { Currency = "EUR", Amount = 100m } }
}
public static void Seed(EntityTypeBuilder<Product> builder)
{
builder.HasData(Products.Select((p, i) => new
{
ProductId = i + 1,
p.Name,
}));
}
public static void Seed(OwnedNavigationBuilder<Product, Money> builder)
{
builder.HasData(Products.Select((p, i) => new
{
ProductId = i + 1,
p.Price.Currency,
p.Price.Amount,
}));
}
}
}对于我来说,这似乎更容易读懂,而且您不必显式地指定ids。
https://stackoverflow.com/questions/70979573
复制相似问题