Ich versuche, eine stark typisierte Id
Klasse zu haben, die jetzt intern 'lang' ist. Implementierung unten. Das Problem, das ich in meinen Entitäten habe, ist, dass Entity Framework mir eine Nachricht gibt, dass die Eigenschafts- ID bereits darauf abgebildet ist. Siehe meine IEntityTypeConfiguration
unten.
Hinweis: Ich strebe keine starre DDD-Implementierung an. Bitte beachten Sie dies beim Kommentieren oder Beantworten . Die gesamte ID hinter der Eingabe Id
ist für Entwickler gedacht, die zu dem Projekt kommen. Sie sind stark typisiert, um die ID in all ihren Entitäten zu verwenden, natürlich übersetzt in long
(oder BIGINT
) - aber dann ist es für andere klar.
Unterhalb der Klasse & Konfiguration, was nicht funktioniert. Das Repo finden Sie unter https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31 ,
Id
Klasse unter (jetzt auskommentiert ): https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/blob/master/Source/Common/Kf.CANetCore31/DomainDrivenDesign/Id.csEntity
undValueObject
Klassen (wobei für eineEntity
die EigenschaftId
vom TypId
.cs (oben) war: https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/tree/master/Source/Common/Kf.CANetCore31/DomainDrivenDesign- Konfigurationen unter: https://github.com/KodeFoxx/Kf.CleanArchitectureTemplate.NetCore31/tree/master/Source/Infrastructure/Persistence/Kf.CANetCore31.Infrastructure.Persistence.Ef/EntityTypeConfigurations
Id
Klassenimplementierung (jetzt als veraltet markiert, da ich die Idee aufgegeben habe, bis ich eine Lösung dafür gefunden habe)
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
Ich habe verwendetPerson
, wenn die ID für die Entität nicht als veraltet markiert ist. Leider wollte EfCore sie nicht zuordnen, wenn sie vom Typ ID war. Wenn sie vom Typ lang war, war dies kein Problem. Andere Typen im Besitz, wie Sie sehen (mit Name
) funktioniert gut.
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
Basisklasse (als ich noch Id verwendete, also als es nicht als veraltet markiert war)
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
(Die Domain und Verweise auf die anderen ValueObjects finden Sie unter 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
... verlieren oder müsste sie dann anderweitig in einer Erweiterungsmethode implementieren ... Ich mag die Idee, danke zum Mitdenken. Wenn keine andere Lösung gefunden wird, würde ich mich damit zufrieden geben, da dies eindeutig die Absicht besagt.Nachdem ich lange gesucht und versucht hatte, eine weitere Antwort zu erhalten, fand ich sie, hier ist sie dann. Vielen Dank an Andrew Lock.
Stark typisierte IDs in EF Core: Verwenden stark typisierter Entitäts-IDs, um primitive Besessenheit zu vermeiden - Teil 4 : https://andrewlock.net/strongly-typed-ids-in-ef-core-using-strongly-typed-entity- IDs-um-primitive-Besessenheit-zu-vermeiden-Teil-4 /
TL; DR / Zusammenfassung von Andrew In diesem Beitrag beschreibe ich eine Lösung für die Verwendung stark typisierter IDs in Ihren EF Core-Entitäten mithilfe von Wertkonvertern und einem benutzerdefinierten IValueConverterSelector. Der BasiswertConverterSelector im EF Core-Framework wird verwendet, um alle integrierten Wertkonvertierungen zwischen primitiven Typen zu registrieren. Durch Ableiten von dieser Klasse können wir unsere stark typisierten ID-Konverter zu dieser Liste hinzufügen und eine nahtlose Konvertierung in allen EF Core-Abfragen erzielen
quelle
Ich denke du hast kein Glück. Ihr Anwendungsfall ist äußerst selten. Und EF Core 3.1.1 hat immer noch Probleme damit, SQL in die Datenbank zu integrieren, die nur in den meisten Basisfällen fehlerhaft ist.
Sie müssten also etwas schreiben, das durch den LINQ-Baum geht, und dies ist wahrscheinlich eine enorme Menge an Arbeit, und wenn Sie auf Fehler in EF Core stoßen - was Sie werden -, haben Sie Spaß daran, dies in Ihren Tickets zu erklären.
quelle