'Entity Framework. How to map class with nested Enumeration class
I am using an Enumeration class like this
public class SizeUnit : Enumeration {
public static SizeUnit Inch = new SizeUnit(1, nameof(Inch));
public static SizeUnit Centimeter = new SizeUnit(2, nameof(Centimeter));
private SizeUnit(int id, string name) : base(id, name) {}
}
I have another class that references SizeUnit
public class ValueUnit {
public decimal Value { get; private set; }
public SizeUnit Unit { get; private set; }
public ValueUnit(decimal value, SizeUnit unit) {
Value = Decimal.Round(value, 2);
Unit = unit;
}
}
I have entity class that references ValueUnit
public sealed class Item : EntityAudit {
public ValueUnit Height { get; private set; }
public ValueUnit Weight { get; private set; }
public Item(ValueUnit height, ValueUnit weight) {
SetHeight(height);
SetWeight(weight);
}
public void SetHeight(ValueUnit height){
if (!height.Unit.Equals(SizeUnit.Centimeter) && !height.Unit.Equals(SizeUnit.Inch))
throw new ArgumentException("Height must be in centimeter or inch");
Height = height;
}
public void SetWeight(ValueUnit weight){
if (!weight.Unit.Equals(SizeUnit.Kilogram) && !weight.Unit.Equals(SizeUnit.Pound))
throw new ArgumentException("Weight must be in kilogram or pound");
Weight = Weight;
}
}
And I have configuration on DB context
builder.Entity<SizeUnit>().ToTable("VO_SizeUnit").HasData(Enumeration.GetAll<SizeUnit>());
public class ItemEntityTypeConfiguration : IEntityTypeConfiguration<Item> {
public void Configure(EntityTypeBuilder<Item> builder) {
builder.ToTable("Items");
builder.OwnsOne(app => app.Height,
navigationBuilder =>
{
navigationBuilder.Property(size => size.Value)
.HasColumnName("HeightValue");
navigationBuilder.HasOne<SizeUnit>(unit => unit.Unit)
.WithMany()
.HasForeignKey("UnitId");
});
builder.OwnsOne(app => app.Weight,
navigationBuilder =>
{
navigationBuilder.Property(size => size.Value)
.HasColumnName("WeightValue");
navigationBuilder.HasOne<SizeUnit>(unit => unit.Unit)
.WithMany
.HasForeignKey("UnitId");
});
}
}
After creating a new Item, DB context tries to create a new SizeUnit instead of setting a foreign key to SizeUnit table.
I get an error:
MessageText: duplicate key value violates unique constraint "PK_VO_SizeUnit"
What is the best way to make the HeightUnitId, WeightUnitId fields automatically refer to SizeUnit when creating an Item?
UPD: Enumeration class https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/enumeration-classes-over-enum-types
public abstract class EntityAudit {
[Key]
public Guid Id { get; protected set; }
public override bool Equals(object obj) {
var compareTo = obj as Entity;
if (ReferenceEquals(this, compareTo))
return true;
if (compareTo is null) return false;
return Id.Equals(compareTo.Id);
}
public static bool operator ==(Entity a, Entity b) {
if (a is null && b is null)
return true;
if (a is null || b is null) return false;
return a.Equals(b);
}
public static bool operator !=(Entity a, Entity b) {
return !(a == b);
}
public override int GetHashCode() {
return GetType().GetHashCode() * 907 + Id.GetHashCode();
}
public override string ToString() {
return GetType().Name + " [Id=" + Id + "]";
}
public DateTimeOffset CreatedDate { get; set; }
public DateTimeOffset UpdatedDate { get; set; }
public DateTimeOffset? DeletedDate { get; set; }
public Guid? CreatedBy { get; set; }
public Guid? UpdatedBy { get; set; }
public Guid? DeletedBy { get; set; }
public bool IsDeleted { get; set; }
}
UPD v2: I solved this problem in this way.
public sealed class Item : EntityAudit {
[Column("HeightValue")]
public decimal HeightValue { get; private set; }
[Column("HeightUnitId")]
public int HeightUnitId { get; private set; }
[Column("WeightValue")]
public decimal WeightValue { get; private set; }
[Column("WeightUnitId")]
public int WeightUnitId { get; private set; }
public ValueUnit Height { get; private set; }
public ValueUnit Weight { get; private set; }
}
public class ItemEntityTypeConfiguration : IEntityTypeConfiguration<Item> {
public void Configure(EntityTypeBuilder<Item> builder) {
builder.ToTable("Items");
builder.OwnsOne(app => app.Height,
navigationBuilder =>
{
navigationBuilder.Property(size => size.Value)
.HasColumnName("HeightValue");
navigationBuilder
.HasOne(e => e.Unit)
.WithMany()
.HasForeignKey("HeightUnitId");
navigationBuilder
.Property("HeightUnitId")
.HasColumnName("HeightUnitId");
});
builder.OwnsOne(app => app.Weight,
navigationBuilder =>
{
navigationBuilder.Property(size => size.Value)
.HasColumnName("WeightValue");
navigationBuilder
.HasOne(e => e.Unit)
.WithMany()
.HasForeignKey("WeightUnitId");
navigationBuilder
.Property("WeightUnitId")
.HasColumnName("WeightUnitId");
});
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|