Yve*_*lpe 11 c# domain-driven-design entity-framework entity-framework-core .net-core
我正在尝试创建一个强类型Id类,它现在在内部保存“long”。下面实现。我在实体中使用它的问题是实体框架给了我一条消息,表明属性Id已经映射到它上面。IEntityTypeConfiguration下面看我的。
注意:我的目标不是严格的 DDD 实现。所以请在评论或回答时记住这一点。类型化背后的整个 idId是供开发人员使用的,他们被强类型化为在所有实体中使用 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/DomainDrivenDesignId类实现(现在标记为过时,因为在找到解决方案之前我放弃了这个想法)
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 };
}
}
Run Code Online (Sandbox Code Playgroud)
EntityTypeConfiguration我正在使用当 Id 没有标记为实体的过时Person不幸的是,当类型为 Id 时,EfCore 不想映射它......当类型为 long 时它没问题......其他拥有的类型,如您所见(带有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);
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
So after searching a long while, and trying to get some more answer, I found it, here it is then. Thanks to Andrew Lock.
Strongly-typed IDs in EF Core: Using strongly-typed entity IDs to avoid primitive obsession - Part 4: https://andrewlock.net/strongly-typed-ids-in-ef-core-using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-4/
TL;DR / Andrew 的摘要 在这篇文章中,我描述了一种通过使用值转换器和自定义 IValueConverterSelector 在 EF Core 实体中使用强类型 ID 的解决方案。EF Core 框架中的基础 ValueConverterSelector 用于注册基元类型之间的所有内置值转换。通过从此类派生,我们可以将强类型 ID 转换器添加到此列表,并在整个 EF Core 查询中获得无缝转换
| 归档时间: |
|
| 查看次数: |
1103 次 |
| 最近记录: |