Innanzitutto, ecco un semplice modello di database di esempio, con Products
assegnati alle Categories
, dove CategoryId
in Products
è la relazione FK con Categories
.
Prodotti :
categorie
Per il modello di dati dell'applicazione .NET, solo una rappresentazione de-normalizzata di un Product
è definita come una classe di entità:
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
Non è stata definita una Category
categoria e, per questo esempio, nessuno è pianificato.
Nella classe DbContext
code-first Entity Framework, ho impostato il set di entità DbSet<Product> Products
:
public virtual DbSet<Product> Products { get; set; }
E in EntityTypeConfiguration
, sto tentando di collegarlo, ma non sono in grado di farlo funzionare correttamente:
public class ProductConfiguration : EntityTypeConfiguration<Product>
{
public ProductConfiguration()
{
HasKey(t => t.ProductId);
// How do I instruct EF to pull just the column 'CategoryName'
// from the FK-related Categories table?
}
}
Mi rendo conto che è possibile creare una vista SQL e quindi direi a EF di mappare a quella vista usando ToTable("App1ProductsView")
, ma in questo esempio, vorrei evitare di farlo.
In una soluzione SQL ADO.NET ORM, non ci sono problemi qui. Posso semplicemente scrivere la mia istruzione SQL per eseguire le INNER JOIN Categories c ON c.CategoryId = p.CategoryId
join. Come posso utilizzare l'API Fluent in codice EF per eseguire lo stesso join interno quando si popola l'entità?
Nella mia ricerca, ho visto un sacco di argomenti "entità divise su più tabelle", ma questo non è quello. Categorie e prodotti sono due entità distinte (dal punto di vista del database), ma il codice .NET è destinato a rimanere ignaro di ciò.
Tentativo fallito 1 :
Questo non funziona e produce una strana query (vista con SQL Server Profiler).
Config Fluent:
Map(m =>
{
m.Property(t => t.CategoryName);
m.ToTable("Categories");
});
SQL risultante:
SELECT
[Extent1].[ProductId] AS [ProductId],
[Extent2].[ProductName] AS [ProductName],
[Extent2].[CategoryId] AS [CategoryId],
[Extent1].[CategoryName] AS [CategoryName],
FROM [dbo].[Categories] AS [Extent1]
INNER JOIN [dbo].[Product1] AS [Extent2] ON [Extent1].[ProductId] = [Extent2].[ProductId]
Risposta breve: MS EF6 non è progettato per questo, non è possibile farlo facilmente.
Si prega di leggere le chiavi , le relazioni e come configurare una relazione uno-a-molti .
EF si aspetta che la tua entità abbia una chiave che fa parte di una tabella mappata. È possibile utilizzare la divisione, ovvero inserire alcune proprietà in Table1 e altre in Table2, ma solo se entrambe le tabelle condividono la stessa chiave primaria. Funziona solo per le relazioni [1] -> [0..1]. Quello che hai è uno-a-molti.
Il modo EF per mappare il tuo schema db è creare due entità e accedere al nome della categoria come Product.Category.Name
.
Se non si desidera esporre l'entità della categoria , è possibile utilizzare una classe interna e una proprietà protetta, esponendo il nome della categoria come una public string CategoryName => this.Category?.Name
proprietà ignorata di sql public string CategoryName => this.Category?.Name
.
L'altra opzione è usare SqlQuery non tracciato . Quindi dovrai scrivere tu stesso una query SQL, come hai fatto per la pura soluzione ADO.NET.
Se non si desidera utilizzare il rilevamento delle modifiche EF, le relazioni e così via, prendere in considerazione un ORM più leggero come Dapper, linq2db o BLToolkit.