Id
내부적으로 ‘long’을 유지 하는 강력한 형식의 클래스를 만들려고합니다 . 아래 구현. 내 엔터티에서 이것을 사용하는 데있어 문제는 Entity Framework 에서 속성 ID 가 이미 매핑되어 있다는 메시지를 표시한다는 것입니다. IEntityTypeConfiguration
아래를 참조하십시오 .
참고 : 엄격한 DDD 구현을 목표로하지 않습니다. 따라서 의견을 말하거나 대답 할 때이 점을 명심 하십시오 . 유형이 지정된 뒤 전체 ID는 Id
그들이 강력 코스 번역의 그 모든 엔티티에서 ID를 사용하는 입력하고 프로젝트에 오는 개발자를위한 것입니다 long
(또는 BIGINT
) – 그러나 다른 사람을 위해 다음 분명하다.
클래스 및 구성 아래에서 작동하지 않습니다. 리포지는 https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31 에서 찾을 수 있습니다 .
Id
클래스 (지금 주석 처리됨) : https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/blob/master/Source/Common/Kf.CANetCore31/DomainDrivenDesign/Id.csEntity
및ValueObject
클래스 (Entity
속성Id
이Id
.cs 유형 임) : https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/tree/master/Source/Common/Kf.CANetCore31/DomainDrivenDesign- https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/tree/master/Source/Infrastructure/Persistence/Kf.CANetCore31.Infrastructure.Persistence.Ef/EntityTypeConfigurations의 구성
Id
클래스 구현 (지금은 해결책을 찾을 때까지 아이디어를 포기했기 때문에 더 이상 사용되지 않음으로 표시됨)
namespace Kf.CANetCore31.DomainDrivenDesign
{
[DebuggerDisplay("{DebuggerDisplayString,nq}")]
[Obsolete]
public sealed class Id : ValueObject
{
public static implicit operator Id(long value)
=> new Id(value);
public static implicit operator long(Id value)
=> value.Value;
public static implicit operator Id(ulong value)
=> new Id((long)value);
public static implicit operator ulong(Id value)
=> (ulong)value.Value;
public static implicit operator Id(int value)
=> new Id(value);
public static Id Empty
=> new Id();
public static Id Create(long value)
=> new Id(value);
private Id(long id)
=> Value = id;
private Id()
: this(0)
{ }
public long Value { get; }
public override string DebuggerDisplayString
=> this.CreateDebugString(x => x.Value);
public override string ToString()
=> DebuggerDisplayString;
protected override IEnumerable<object> EquatableValues
=> new object[] { Value };
}
}
EntityTypeConfiguration
아이디 엔티티에 대한 오래된 것으로 표시하지 않을 때 내가 사용했다Person
불행하게도하지만, EfCore가 오랫동안 아무 문제 … 다른 소유 유형 없을 때 유형의 당신이 (함께 보는 바와 같이, … 매핑하지 않은 경우 유형 ID의 Name
) 잘 작동합니다.
public sealed class PersonEntityTypeConfiguration
: IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
// this would be wrapped in either a base class or an extenion method on
// EntityTypeBuilder<TEntity> where TEntity : Entity
// to not repeated the code over each EntityTypeConfiguration
// but expanded here for clarity
builder
.HasKey(e => e.Id);
builder
.OwnsOne(
e => e.Id,
id => {
id.Property(e => e.Id)
.HasColumnName("firstName")
.UseIdentityColumn(1, 1)
.HasColumnType(SqlServerColumnTypes.Int64_BIGINT);
}
builder.OwnsOne(
e => e.Name,
name =>
{
name.Property(p => p.FirstName)
.HasColumnName("firstName")
.HasMaxLength(150);
name.Property(p => p.LastName)
.HasColumnName("lastName")
.HasMaxLength(150);
}
);
builder.Ignore(e => e.Number);
}
}
Entity
기본 클래스 (아직 ID를 사용하고있을 때 사용되지 않는 것으로 표시되지 않은 경우)
namespace Kf.CANetCore31.DomainDrivenDesign
{
/// <summary>
/// Defines an entity.
/// </summary>
[DebuggerDisplay("{DebuggerDisplayString,nq}")]
public abstract class Entity
: IDebuggerDisplayString,
IEquatable<Entity>
{
public static bool operator ==(Entity a, Entity b)
{
if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return false;
return a.Equals(b);
}
public static bool operator !=(Entity a, Entity b)
=> !(a == b);
protected Entity(Id id)
=> Id = id;
public Id Id { get; }
public override bool Equals(object @object)
{
if (@object == null) return false;
if (@object is Entity entity) return Equals(entity);
return false;
}
public bool Equals(Entity other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (GetType() != other.GetType()) return false;
return Id == other.Id;
}
public override int GetHashCode()
=> $"{GetType()}{Id}".GetHashCode();
public virtual string DebuggerDisplayString
=> this.CreateDebugString(x => x.Id);
public override string ToString()
=> DebuggerDisplayString;
}
}
Person
(도메인과 다른 ValueObject에 대한 참조는 https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/tree/master/Source/Core/Domain/Kf.CANetCore31.Core.Domain/People 에서 찾을 수 있습니다 )
namespace Kf.CANetCore31.Core.Domain.People
{
[DebuggerDisplay("{DebuggerDisplayString,nq}")]
public sealed class Person : Entity
{
public static Person Empty
=> new Person();
public static Person Create(Name name)
=> new Person(name);
public static Person Create(Id id, Name name)
=> new Person(id, name);
private Person(Id id, Name name)
: base(id)
=> Name = name;
private Person(Name name)
: this(Id.Empty, name)
{ }
private Person()
: this(Name.Empty)
{ }
public Number Number
=> Number.For(this);
public Name Name { get; }
public override string DebuggerDisplayString
=> this.CreateDebugString(x => x.Number.Value, x => x.Name);
}
}
답변
엄격한 DDD 구현을 목표로하지 않습니다. 따라서 의견을 말하거나 대답 할 때이 점을 명심하십시오. 형식화 된 ID 뒤에있는 전체 ID는 개발자가 모든 엔터티에서 ID를 사용하도록 강력하게 형식화 된 프로젝트에 오는 개발자를위한 것입니다.
그렇다면 왜 타입 별칭을 추가하지 않겠습니까?
using Id = System.Int64;
답변
그래서 오랜 시간 동안 검색하고 더 많은 답변을 얻으려고 노력한 후에 나는 그것을 찾았습니다. Andrew Lock에게 감사합니다.
EF Core의 강력한 유형의 ID : 강력한 유형의 엔티티 ID를 사용하여 원시적 인 집착을 피 하십시오 -4 부 : https://andrewlock.net/strongly-typed-ids-in-ef-core-using-strongly-typed-entity- ids-to-avoid-primitive-obsession-part-4 /
TL; DR / 앤드류 요약
이 글에서는 값 변환기와 사용자 정의 IValueConverterSelector를 사용하여 EF Core 엔티티에서 강력한 유형의 ID를 사용하는 솔루션에 대해 설명합니다. EF Core 프레임 워크의 기본 ValueConverterSelector는 기본 유형 사이의 모든 내장 값 변환을 등록하는 데 사용됩니다. 이 클래스를 통해 강력한 형식의 ID 변환기를이 목록에 추가하고 EF Core 쿼리 전체에서 원활하게 변환 할 수 있습니다.
답변
운이 나쁘다고 생각합니다. 사용 사례는 매우 드 rare니다. 그리고 EF Core 3.1.1은 여전히 가장 기본적인 경우를 제외하고는 손상되지 않은 데이터베이스에 SQL을 배치하는 데 어려움을 겪고 있습니다.
따라서 LINQ 트리를 통과하는 무언가를 작성해야 할 것입니다.이 작업은 엄청난 양의 작업 일 것입니다 .EF Core의 버그에 걸려 넘어지면 티켓에서 설명하는 것이 재미 있습니다.