I have a value object and an entity that uses said value object. I'm using the null-object pattern for said value object. My value object looks something like the following:
public class Reference {
public static Reference Empty;
private string _value;
static Reference() {
Empty = new Reference(String.Empty);
}
public Reference(string value) {
_value = value;
}
private Reference() {
_value = default!;
}
public string Value => _value;
}
And my entity:
public class Payment {
private Guid _id;
private decimal _amount;
private Reference _reference;
public Payment(decimal amount) {
_id = Guid.Empty; //ef will generate the id
_reference = Reference.Empty;
_amount = amount;
}
private Payment() {
_id = default;
_reference = default!;
_amount = default;
}
public Guid Id => _id;
public decimal Amount => _amount;
public Reference Reference => _reference;
}
Now, the class Reference
is configured in EF-Core using OwnsOne
relationship. Something like this:
internal class PaymentConfiguration
: IEntityTypeConfiguration<Payment> {
public void Configure(EntityTypeBuilder<Payment> builder) {
builder.ToTable("Payments");
builder.HasKey(x => x.Id);
builder.OwnsOne(x => x.Reference, y => {
y.Property(z => z.Value)
.HasColumnName("Reference")
.IsRequired();
});
}
}
Adding a payment looks like the following:
var payment = new Payment(5000m);
_context.Payments.Add(payment);
await _context.SaveChangesAsync();
This works pretty well, but the moment I try to add two payments:
_context.Payments.Add(new Payment(5000m));
_context.Payments.Add(new Payment(6000m));
await _context.SaveChangesAsync();
I get an error with the following message:
The property 'PaymentId' on entity type 'Reference' is part of a key and so cannot be modified or marked as modified. To change the principal of an existing entity with an identifying foreign key first delete the dependent and invoke 'SaveChanges' then associate the dependent with the new principal.
After so much debugging, I found out that the problem is that both Payment
objects uses the same reference object defined by Reference.Empty
. Indeed, if I change my code to the following, the problem stops:
public Payment(decimal amount) {
_id = Guid.Empty; //ef will generate the id
_reference = new Reference(String.Empty); //instead of Reference.Empty;
_amount = amount;
}
I don't know the inner workings of EF-Core, but if I had to guess, I'd say that somehow EF-Core creates a derived class and adds stuff to make it work, therefore my Reference.Empty
object is changed thus affecting every Payment
object using it. This means that I cannot use the null-object pattern as is.
Now, my question. Is there a way to configure Ef-Core to stop this behaviour? Or is there a workaround for using the null-object pattern? I'm using C#8, .NET Core 3 and Entity Framework Core 3. Thanks in advance.