学海无涯

导航

ValueObject 值对象

值对象:指实体类中,有的多个属性的关系密码不可分,但又不能独立作为实体类,因为这些属性依护属于实体。例如:位置 Location 包含 经度 longitude 和 纬度 latiude

在 EFCore 中提供了对于没有标识符的值对象进行映射的功能,即“从属实体类(owned entities)类型,我们只要在主实体类中声明从属实体类型的属性,然后使用 Fluent API 中的 OwnsOnet 等方法配置。

using CleanArchitectureApp.SharedKernel;
using CleanArchitectureApp.SharedKernel.Interfaces;

namespace CleanArchitectureApp.Core.RegionAggregate;
public class Region : EntityBase, IAggregateRoot
{
  public MultilingualString Name { get; init; }
  public Area Area { get; init; }
  public RegionLevel Level { get; private set; }
  public Int64? Population { get; private set; }
  public Geo Location { get; set; }
  private Region() { }
  public Region(MultilingualString name, Area area, Geo location, RegionLevel level)
  {
    this.Name = name;
    this.Area = area;
    this.Location = location;
    this.Level = level;
  }
  public void ChangePopulation(long value)
  {
    this.Population = value;
  }
  public void ChangeLevel(RegionLevel value)
  {
    this.Level = value;
  }
}
public record MultilingualString(string Chinese, string? English);
public record Area(double Value, AreaType Unit);
public enum AreaType { SquareKM, Hectare, CnMu };
public enum RegionLevel { Province, City, County, Town };
public record Geo
{
  public double Longitude { get; set; }
  public double Latitude { get; set; }
  public Geo(double longitude, double latitude)
  {
    if (longitude < -180 || longitude > 180)
    {
      throw new ArgumentException("longitude invalid");
    }
    if (latitude < -90 || latitude > 90)
    {
      throw new ArgumentException("latitude invalid");
    }
    Longitude = longitude;
    Latitude = latitude;
  }
}

  

using CleanArchitectureApp.Core.RegionAggregate;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace CleanArchitectureApp.Infrastructure.Data.Config;
public class RegionConfig : IEntityTypeConfiguration<Region>
{
  public void Configure(EntityTypeBuilder<Region> builder)
  {
    builder.OwnsOne(c => c.Area, nb =>
    {
      nb.Property(e => e.Unit).HasMaxLength(20)
      .IsUnicode(false).HasConversion<string>();
    });
    builder.OwnsOne(c => c.Location);
    builder.Property(c => c.Level).HasMaxLength(20)
      .IsUnicode(false).HasConversion<string>();
    builder.OwnsOne(c => c.Name, nb =>
    {
      nb.Property(e => e.English).HasMaxLength(20).IsUnicode(false);
      nb.Property(e => e.Chinese).HasMaxLength(20).IsUnicode(true);
    });
  }
}

  

using CleanArchitectureApp.Core.RegionAggregate;
using CleanArchitectureApp.SharedKernel.Interfaces;
using Microsoft.AspNetCore.Mvc;

namespace CleanArchitectureApp.Web.Api;
[Route("api/[controller]")]
[ApiController]
public class RegionController : ControllerBase
{
  private readonly ILogger<RegionController> _logger;
  private readonly IRepository<Region> _repository;

  public RegionController(ILogger<RegionController> logger, IRepository<Region> repository)
  {
    _logger = logger;
    _repository = repository;
  }
  [HttpPost]
  public async Task<ActionResult<Region>> Create()
  {
    MultilingualString name1 = new MultilingualString("北京", "BeiJing");
    Area area1 = new Area(16410, AreaType.SquareKM);
    Geo loc = new Geo(116.4074, 39.904);
    Region c1 = new Region(name1, area1, loc, RegionLevel.Province);
    c1.ChangePopulation(21893100);
    Region newRegion = await _repository.AddAsync(c1);
    return Ok(newRegion);
  }
  [HttpGet]
  public async Task<ActionResult<IEnumerable<Region>>> GetList()
  {
    var list = await _repository.ListAsync();
    return Ok(list);
  }

}

  跟据实体生成的表结构:

 

 

 

posted on 2022-11-02 15:05  宁静致远.  阅读(195)  评论(0编辑  收藏  举报