[모범 사례] EF Core 6을 사용하여 DDD 값 개체로 C# 9 레코드
21201 단어 csharpdatabasedotnetarchitecture
Antonio Falcao / Dotnet 6.EF Core 6.Record.Value 개체
이 프로젝트는 EF Core 6을 사용하여 레코드를 값 개체로 구성하고 사용하는 것을 보여 주는 것을 목표로 합니다.
가치 객체
값 개체는 동일성이 ID를 기반으로 하지 않는 단순한 엔터티를 나타내는 작은 개체입니다. 두 개의 값 개체는 동일한 값을 가질 때 동일하며 반드시 동일한 개체일 필요는 없습니다.
주요 특징:
기록
데이터 캡슐화를 위한 기본 제공 기능을 제공하는 참조 형식을 정의합니다. 변경할 수 없는 속성이 있는 유형
record
을 생성할 수 있습니다.불변성
A
record
유형이 반드시 변경할 수 있는 것은 아닙니다. 읽기 전용이 아닌 set 접근자와 필드를 사용하여 속성을 선언할 수 있습니다. 그러나 레코드는 변경할 수 있지만 변경할 수 없는 데이터 모델을 쉽게 만들 수 있습니다.평등
값 같음은 유형이 일치하고 모든 속성 및 필드 값이 일치하는 경우
record
유형의 두 변수가 같음을 의미합니다. 다른 참조 유형의 경우 같음은 ID를 의미합니다. 즉, 참조 유형의 두 변수는 동일한 개체를 참조하는 경우 동일합니다.record
유형의 값 개체의 경우 기본적으로 합성된 같음 멤버는 다음과 같습니다.class R1 : IEquatable<R1>
{
public T1 P1 { get; init; }
protected virtual Type EqualityContract => typeof(R1);
public override bool Equals(object? obj) => Equals(obj as R1);
public virtual bool Equals(R1? other)
{
return !(other is null) &&
EqualityContract == other.EqualityContract &&
EqualityComparer<T1>.Default.Equals(P1, other.P1);
}
public static bool operator==(R1? left, R1? right)
=> (object)left == right || (left?.Equals(right) ?? false);
public static bool operator!=(R1? left, R1? right)
=> !(left == right);
public override int GetHashCode()
{
return Combine(EqualityComparer<Type>.Default.GetHashCode(EqualityContract),
EqualityComparer<T1>.Default.GetHashCode(P1));
}
}
EF Core에서 소유 엔터티 형식으로 값 개체 유지
Even with some gaps between the canonical value object pattern in DDD and the owned entity type in EF Core, it's currently the best way to persist value objects with EF Core.
소유 엔터티 형식을 사용하면 도메인 모델에 명시적으로 정의된 자체 ID가 없고 값 개체와 같은 속성으로 사용되는 형식을 매핑할 수 있습니다.
소유된 유형의 인스턴스 ID는 완전히 고유하지 않습니다. 세 가지 구성 요소로 구성됩니다.
실재
public class Person : Entity<Guid>
{
public Person(string name, int age)
=> (Name, Age) = (name, age);
public string Name { get; }
public int Age { get; }
public Address Address { get; private set; }
public void DefineAddress(Address address)
{
if (address is null) throw new BusinessException("Home address must be informed");
// Benefit of the record Equality Contract
if(address.Equals(Address)) return;
Address = address;
}
}
값 개체
public record Address : Abstractions.ValueObject
{
// Empty constructor in this case is required by EF Core,
// because has a complex type as a parameter in the default constructor.
private Address() { }
public Address(Street street, string zipCode)
=> (Street, ZipCode) = (street, zipCode);
public Street Street { get; private init; }
public string ZipCode { get; private init; }
}
구성
관계형 데이터베이스에 필요한 관계를 해결하기 위해서는 식별자를 섀도우 속성으로 정의해야 합니다.
public class PersonConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.HasKey(user => user.Id);
...
// Configures a relationship where the Address is owned by (or part of) Person.
builder.OwnsOne(
person => person.Address,
addressNavigationBuilder =>
{
// Configures a different table that the entity type maps to when targeting a relational database.
addressNavigationBuilder
.ToTable("Addresses");
// Configures the relationship to the owner, and indicates the Foreign Key.
addressNavigationBuilder
.WithOwner()
.HasForeignKey("PersonId"); // Shadow Foreign Key
// Configure a property of the owned entity type, in this case the to be used as Primary Key
addressNavigationBuilder
.Property<Guid>("Id"); // Shadow property
// Sets the properties that make up the primary key for this owned entity type.
addressNavigationBuilder
.HasKey("Id"); // Shadow Primary Key
// Configures a relationship where the Street is owned by (or part of) Addresses.
// In this case, is not used "ToTable();" to maintain the owned and owner in the same table.
addressNavigationBuilder.OwnsOne(
address => address.Street,
streetNavigationBuilder =>
{
...
// Configures a relationship where the City is owned by (or part of) Street.
// In this case, is not used "ToTable();" to maintain the owned and owner in the same table.
streetNavigationBuilder.OwnsOne(
street => street.City,
cityNavigationBuilder =>
{
...
});
});
});
}
}
스크립트 생성
CREATE TABLE [Persons]
(
[Id] uniqueidentifier NOT NULL,
[Name] varchar(128) NOT NULL,
[Age] int NOT NULL,
CONSTRAINT [PK_Persons] PRIMARY KEY ([Id])
);
CREATE TABLE [Addresses]
(
[Id] uniqueidentifier NOT NULL,
[Street_City_Name] varchar(128) NULL,
[Street_City_State_Country_Initials] varchar(8) NULL,
[Street_City_State_Country_Name] varchar(128) NULL,
[Street_City_State_Initials] varchar(8) NULL,
[Street_City_State_Name] varchar(128) NULL,
[Street_Name] varchar(128) NULL,
[Street_Number] int NULL,
[ZipCode] varchar(32) NULL,
[PersonId] uniqueidentifier NOT NULL,
CONSTRAINT [PK_Addresses] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Addresses_Persons_PersonId] FOREIGN KEY ([PersonId]) REFERENCES [Persons] ([Id]) ON DELETE CASCADE
);
CREATE UNIQUE INDEX [IX_Addresses_PersonId] ON [Addresses] ([PersonId]);
EF Core를 사용하여 고아 값 개체 삭제
상위 및 하위 엔터티 간의 관계는 필수 또는 선택 사항일 수 있습니다. 필수관계란 자식은 부모 없이는 존재할 수 없다는 것을 의미하며, 부모가 삭제되거나 자식과 부모의 관계가 단절되면 자식은 고아가 된다. 이 경우 EF Core는 자동으로 하위 삭제를 수행합니다.
Antonio Falcao / Dotnet 6.EF Core 6.Record.Value 개체
이 프로젝트는 EF Core 6을 사용하여 레코드를 값 개체로 구성하고 사용하는 것을 보여 주는 것을 목표로 합니다.
Reference
이 문제에 관하여([모범 사례] EF Core 6을 사용하여 DDD 값 개체로 C# 9 레코드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/antoniofalcao/best-practice-c-9-records-as-ddd-value-objects-with-ef-core-6-502p텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)