Estoy tratando de tener una Id
clase fuertemente tipada , que ahora tiene "largo" internamente. Implementación a continuación. El problema que tengo al usar esto en mis entidades es que Entity Framework me da un mensaje de que el ID de la propiedad ya está asignado. Ver mi a IEntityTypeConfiguration
continuación.
Nota: No pretendo tener una implementación DDD rígida. Por lo tanto, tenga esto en cuenta al comentar o responder . Toda la identificación detrás de lo escrito Id
es para los desarrolladores que vienen al proyecto, están fuertemente escritos para usar Id en todas sus entidades, por supuesto traducido a long
(o BIGINT
), pero está claro para otros.
Debajo de la clase y configuración, que no funciona. El repositorio se puede encontrar en https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31 ,
Id
clase en (comentado ahora): https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/blob/master/Source/Common/Kf.CANetCore31/DomainDrivenDesign/Id.csEntity
yValueObject
clases (donde para unaEntity
propiedadId
era del tipoId
.cs (arriba): https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/tree/master/Source/Common/Kf.CANetCore31/DomainDrivenDesign- Configuraciones en: https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/tree/master/Source/Infrastructure/Persistence/Kf.CANetCore31.Infrastructure.Persistence.Ef/EntityTypeConfigurations
Id
implementación de clase (marcada como obsoleta ahora, porque abandoné la idea hasta que encontré una solución para esto)
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
Estaba usando cuando Id no marcado como obsoleto para la entidad.Person
Desafortunadamente, cuando era de tipo Id, EfCore no quería mapearlo ... cuando era de tipo largo no era problema ... Otros tipos de propiedad, como puede ver (con Name
) trabaja bien.
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
clase base (cuando todavía estaba usando Id, entonces cuando no estaba marcado como obsoleto)
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
(el dominio y las referencias a los otros ValueObjects se pueden encontrar en 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);
}
}
Id.Empty
..., o tendría que implementarlo de otra manera en un método de extensión entonces ... Me gusta la idea, gracias por pensar. Si no surge ninguna otra solución, me conformaría con esto, ya que esto indica claramente la intención.Entonces, después de buscar mucho tiempo, y tratando de obtener una respuesta más, la encontré, aquí está entonces. Gracias a Andrew Lock.
ID fuertemente tipados en EF Core: uso de ID de entidad fuertemente tipados para evitar la obsesión primitiva - Parte 4 : https://andrewlock.net/strongly-typed-ids-in-ef-core-using-strongly-typed-entity- ids-to-evitar-primitive-obsession-part-4 /
TL; DR / Resumen de Andrew En esta publicación describo una solución para usar ID fuertemente tipados en sus entidades EF Core mediante el uso de convertidores de valor y un IValueConverterSelector personalizado. El ValueConverterSelector base en el marco de EF Core se usa para registrar todas las conversiones de valor incorporadas entre tipos primitivos. Al derivar de esta clase, podemos agregar nuestros convertidores de ID fuertemente tipados a esta lista y obtener una conversión perfecta en todas nuestras consultas de EF Core
fuente
Creo que no tienes suerte. Su caso de uso es extremadamente raro. Y EF Core 3.1.1 todavía está luchando para poner SQL en la base de datos que no está roto en nada, excepto en la mayoría de los casos base.
Por lo tanto, tendrías que escribir algo que pase por el árbol LINQ y esto probablemente sea una gran cantidad de trabajo, y si te topas con errores en EF Core, lo cual harás, te divertirás explicando eso en tus tickets.
fuente