How to force EF Core to use backing field of property that this target of a relationship

c# entity-framework-core

Question

I want to configure a property to be the target of a relationship, but I do not want the getter or setter to be used by EF when object is materialized, because I have some business logic there.

DispatchItem.cs:

public class DispatchItem {
    private PurchaseOrderItem _purchaseOrderItem;

    public PurchaseOrderItem PurchaseOrderItem {
        get => _purchaseOrderItem;
        set {
            _purchaseOrderItem = value;
            throw new Exception("This shouldn't be called");
        }
    }
    public Guid? PurchaseOrderItemId { get; set; }

}

I have configured the backing field like this (DBContext.cs):

modelBuilder.Entity<DispatchItem>().Property(di => di.PurchaseOrderItem).UsePropertyAccessMode(PropertyAccessMode.Field);
modelBuilder.Entity<DispatchItem>().Property(di => di.PurchaseOrderItemId).HasColumnName("purchase_order_item_id");
modelBuilder.Entity<DispatchItem>().HasOne(di => di.PurchaseOrderItem).WithMany(poi => poi.DispatchItems).HasForeignKey(di => di.PurchaseOrderItemId);

But it throws:

Exception thrown: 'System.InvalidOperationException' in Microsoft.EntityFrameworkCore.dll
The navigation property 'PurchaseOrderItem' cannot be added to the entity type 'DispatchItem' because a property with the same name already exists on entity type 'DispatchItem'.

If I remove the UsePropertyAccessMode statement, then the setter is used when the object is materialized instead of the backing field.

1
0
6/15/2018 6:08:49 PM

Accepted Answer

It's possible to configure a backing field usage for a navigation property, but not via Property method which is for primitive property, and not via fluent API (doesn't exist at this time), but directly through mutable model metadata associated with the relationship:

modelBuilder.Entity<PurchaseOrder>()
    .HasMany(e => e.LineItems)
    .WithOne(e => e.PurchaseOrder) // or `WithOne() in case there is no inverse navigation property
    .Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field); // <--

You can also set the mode for all entity navigation properties (you can still override it for individual properties) by using:

modelBuilder.Entity<PurchaseOrder>()
    .Metadata.SetNavigationAccessMode(PropertyAccessMode.Field);
2
6/12/2018 10:31:23 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow