Ho una classe Product
, che contiene una proprietà Picture
. Altre classi possono anche avere un'immagine, ad esempio un Customer
può avere Picture
.
Product.cs:
public class Product
{
public Picture Picture { get; set; }
}
customer.cs:
public class Customer
{
public Picture Picture { get; set; }
}
Picture.cs:
public class Picture
{
public string Type { get; set; }
public byte[] Content { get; et; }
}
L' immagine è sempre facoltativa , vale a dire che i prodotti e i clienti possono o meno avere un'immagine. Tuttavia, un'immagine è collegata in modo univoco esattamente a un'entità "genitore" (un prodotto o un cliente). Senza il genitore, non c'è alcuna utilità per l'esistenza dell'immagine. Nota che non esiste alcun collegamento da Picture alla classe genitore, perché questo genitore può essere di più tipi (Prodotto o Cliente).
Un altro requisito è che voglio avere il pieno controllo sul fatto che l'immagine sia caricata o meno, attraverso il caricamento desideroso o pigro . Ad esempio, quando si recupera un elenco di prodotti, non voglio che l'immagine venga recuperata, ma se viene richiesto un singolo prodotto, l'immagine deve essere inclusa.
La mia domanda : come posso configurare Entity Framework in modo che:
Sto usando API fluente per definire la relazione. Attualmente, non vi è alcuna cancellazione a cascata di sorta.
public class ProductMap : EntityTypeConfiguration<Product>
{
public ProductMap()
{
ToTable("PRODUCTS");
HasKey(x => x.Id);
HasOptional(x => x.Picture).WithOptionalDependent().Map(m => m.MapKey("PICTUREID"));
}
}
Ho provato a utilizzare WithRequired ma questo genera errori perché non c'è alcun collegamento o chiave esterna da Picture
a Product/Customer
.
puoi fare come segue:
public abstract class Picture
{
public int Id {get;set;}
public string Type { get; set; }
public byte[] Content { get; set; }
}
public class ProductImage:Picture
{
public int ProductId {get;set;}
public virtual Product Product {get;set;}
}
public class CustomerImage:Picture
{
public int CustomerId {get;set;}
public virtual Customer Customer{get;set;}
}
quindi puoi configuer in questo modo: es. per prodotto:
HasOptional(x=>x.ProductImage)
.withRequired(x=>x.Product)
.HasForeignKey(x=>x.ProductId); //cascade on delete is default true
In questo modo puoi caricare l'immagine quando ne hai bisogno, e se elimini l'elemento prodotto, l'immagine verrà eliminata. L'immagine è facoltativa e può essere sostituita. In caso di aggiornamento è necessario specificare una nuova immagine o eliminare la vecchia immagine.
Spero che questa alternativa ti aiuti a scegliere esattamente ciò che desideri.
Penso che puoi configurare Picture
come ComplexType
che renderà le proprietà delle colonne della classe Picture
nella tabella padre.
Questo significa:
Picture
corrispondente viene cancellata. Picture
(dati di immagine aggiornati o nessun dato), vengono aggiornate anche le colonne corrispondenti nella tabella padre. Come è possibile configurare l'entità Picture
come ComplexType
è descritto qui: http://weblogs.asp.net/manavi/entity-association-mapping-with-code-first-part-1-one-to-one-associations .
Minimamente questo è quello che devi fare:
public class MyDbContext:DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.ComplexType<Picture>();
}
}
Se esegui la migration
probabilmente genererà le migrazioni simili al seguente:
public override void Up()
{
CreateTable(
"dbo.Customers",
c => new
{
Id = c.Int(nullable: false, identity: true),
Picture_Type = c.String(),
Picture_Content = c.Binary(),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.Products",
c => new
{
Id = c.Int(nullable: false, identity: true),
Picture_Type = c.String(),
Picture_Content = c.Binary(),
})
.PrimaryKey(t => t.Id);
}
Inoltre, puoi scrivere una configurazione fluente per ComplexType
come segue:
public class PictureConfig : ComplexTypeConfiguration<Picture>
{
public PictureConfig()
{
Property(t => t.Type).HasColumnName("PictureType");
Property(t => t.Content).HasColumnName("PictureContent");
}
}
e aggiungi questa configurazione in DbContext
:
public class MyDbContext:DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//modelBuilder.ComplexType<Picture>();
modelBuilder.Configurations.Add(new PictureConfig());
}
}
Se ora add-migration
, potrebbe essere simile al seguente:
public override void Up()
{
CreateTable(
"dbo.Customers",
c => new
{
Id = c.Int(nullable: false, identity: true),
PictureType = c.String(),
PictureContent = c.Binary(),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.Products",
c => new
{
Id = c.Int(nullable: false, identity: true),
PictureType = c.String(),
PictureContent = c.Binary(),
})
.PrimaryKey(t => t.Id);
}
Spero che questo ti aiuti.
Aggiornamento basato sul commento: questa parte dell'aggiornamento non ti dà esattamente quello che vuoi, ma piuttosto un semplice suggerimento.
Penso che tu stia cercando una relazione come la seguente:
Product---1-----1---Picture ---1------1---Customer
|- Id |- Id |- Id
|- PictureId? |- PictureId?
Cioè, si può mantenere l' nullable
PictureId
sulle classi genitore e cambiare questo PictureId
, ogni volta che l'immagine viene cambiata.
Svantaggio: è necessario gestire l'attività di manipolazione dei dati (CRUD) da soli.
Vantaggio: in questo modo hai il pieno controllo su quando caricare l'immagine, in quanto il caricamento del genitore non carica automaticamente l' Picture
. Inoltre, questo ti consente di disaccoppiare l' Picture
dal tuo database e utilizzare una sorta di archivio blob (potrebbe essere in cloud o così).