La relazione tra prodotto e cliente è di tipo molti-a-molti (da un punto di vista una vista).
Usando EF Core, abbiamo diviso questa relazione in due relazioni uno-a-molti con una terza entità: ProductCustomer
public partial class ProductCustomer
{
public long ProductId { get; set; }
public long CustomerId { get; set; }
public virtual Customer Customer { get; set; }
public virtual Product Product { get; set; }
public virtual ICollection<UsageRecord> UsageRecord { get; set; }
}
UsageRecord è un elenco di record contenenti la quantità di dati utilizzati da un determinato cliente durante l'utilizzo di un prodotto
public partial class UsageRecord
{
public long Id { get; set; }
public long ProductId { get; set; }
public long CustomerId { get; set; }
public decimal Quantity { get; set; }
public virtual ProductCustomer ProductCustomer { get; set; }
}
Ora, se provo a leggere un UsageRecord specifico, l'oggetto ProductCustomer è nullo (perfetto, sto usando un approccio di caricamento ansioso)
return _usageRecordEntity.Where(x => x.ProductId == productId).AsEnumerable();
Ma se chiedo esplicitamente di includere () l'entità ProductCustomer , il framwork dell'entità, non include solo tutti i riferimenti ricorsivi, ma include anche l'oggetto Product e NON il cliente !
return _usageRecordEntity.Where(x => x.ProductId == productId).Include(p => p.ProductCustomer).AsEnumerable();
Prima cosa: non capisco perché includa l'intera catena di oggetti se chiedo specificamente solo a ProductCustomer .
Seconda cosa: perché il prodotto e NON il cliente ?!
Includo per completezza il modello di contesto:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>(entity =>
{
entity.Property(e => e.customerId)
.IsRequired()
.HasColumnName("CustomerId")
.HasMaxLength(255);
});
modelBuilder.Entity<Product>(entity =>
{
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(50);
});
modelBuilder.Entity<ProductCustomer>(entity =>
{
entity.HasKey(e => new { e.ProductId, e.CustomerId })
.HasName("PK__ProductCustomerComposite");
entity.HasOne(d => d.Customer)
.WithMany(p => p.ProductCustomer)
.HasForeignKey(d => d.CustomerId)
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("FK__ProductCu__CustomerId");
entity.HasOne(d => d.Product)
.WithMany(p => p.ProductCustomer)
.HasForeignKey(d => d.ProductId)
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("FK__ProductCu__ProductId");
});
modelBuilder.Entity<UsageRecord>(entity =>
{
entity.Property(e => e.Quantity)
.HasColumnType("decimal")
.HasDefaultValueSql("0");
entity.HasOne(d => d.ProductCustomer)
.WithMany(p => p.UsageRecord)
.HasForeignKey(d => new { d.ProductId, d.CustomerId })
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("FK_UsageRecordProductcustomer");
});
}
Fondamentalmente la risposta è fornita dal seguente suggerimento nella sezione Caricamento dei dati correlati: sezione di caricamento Eager della documentazione di EF Core (il punto saliente è mio):
Entity Framework Core aggiusterà automaticamente le proprietà di navigazione su qualsiasi altra entità precedentemente caricata nell'istanza di contesto. Pertanto, anche se non includi esplicitamente i dati per una proprietà di navigazione, la proprietà potrebbe ancora essere popolata se alcune o tutte le entità correlate fossero state precedentemente caricate.