2013-12-17 15 views
6

Sto sviluppando la mia prima app per framework di entità. Sto usando EF vesion 6 (da Nuget) e .net 4.0. Tuttavia, sto avendo qualche difficoltà con qualcosa che, per me, sembra che dovrebbe essere straordinariamente semplice. Ho trovato molti consigli e soluzioni contrastanti su Internet, ma dopo aver trascorso diversi giorni a cercare di risolvere il problema, sono davvero confuso e sto arrivando al punto di mettere in discussione alcune intese basilari che ho dell'Entity Framework. Quello che voglio fare è questo: creare una semplice raccolta di entità correlate e cancellarle automaticamente quando vengono rimosse dal genitore.Entity Framework 6 e collezioni

Ecco come modellerei questo in vanilla C#. In linea con i campioni di Microsoft, supponiamo di avere due classi, delle poste e tag, in questo modo:

public class Post 
{ 
    public string Name { get; set; } 
    public string Author { get; set; } 

    public ICollection<Tag> Tags { get; set; } 
} 

public class Tag 
{ 
    public string Text { get; set; } 
    // Possibly other properties here 
} 

Poi, l'aggiunta di un tag è semplice come myPost.Tags.Add(myTag) e la rimozione di un tag è semplice come myPost.Tags.Remove(myTag).

Ora al lato Entity Framework delle cose: l'ho guardato e ho pensato "Chiave straniera, ovviamente!" ma avevo una serie di problemi con l'aggiunta di un FK: i tag non venivano eliminati dal database quando venivano rimossi dal post, myPost.Tags avrebbe 0 elementi se caricati dal db, nonostante l'esploratore SQL che mostrava che il valore PostId era corretto, ecc. Mi sono imbattuto in una serie di trucchi, come contrassegnare lo Tag.PostId come una chiave, rimuovere manualmente i tag, aggiungendo effettivamente tag al contesto come un DbSet, impostando manualmente myTag.Post = null; (ho provato con Lazy caricando sia abilitato che disabilitato, per quello che è vale la pena - anche se mi piacerebbe tenerlo spento se possibile)

Ora (grazie in non piccola parte a esempi apparentemente conflittuali ed eccessivamente complicati), sono abbastanza confuso e perso. Qualcuno può dirmi esattamente come dovrei fare per impostare questa relazione in EF? (Sto usando codice In primo luogo, tra l'altro)

SOLUZIONE:

Grazie a Moho, mi è venuta in mente questa struttura, che fa esattamente quello che voglio:

public class Post 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Author { get; set; } 

    public virtual ICollection<Tag> Tags { get; set; } 

    public Post() 
    { 
     Tags = new HashSet<Tag>(); 
    } 
} 

public class Tag 
{ 
    [Key, Column(Order=1), DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    public string Text { get; set; } 
    // Possibly other properties here 

    public virtual Post Post { get; set; } 
    [Key, Column(Order=2)] 
    public virtual int PostId { get; set; } 
} 

public class TestContext : DbContext 
{ 
    public DbSet<Post> Posts { get; set; } 
} 

Quando un Tag viene rimosso da una tag collezione s' Post, Entity Framework emetterà un DELETE per il tag, come descritto qui (# 2): http://www.kianryan.co.uk/2013/03/orphaned-child/

Allo stesso modo, l'aggiunta di un tag per un post emetterà automaticamente un INSERT e impostare le relazioni FK anca.

Una cosa da notare: assicurati di utilizzare virtual! Penso che sia stata la radice di molte delle mie frustrazioni.

+0

Non hai inserito una proprietà 'Id' e EF ha fatto la relazione? Puoi darci un esempio di come stai facendo le tue domande? – Tico

+0

@Tico Ho omesso le implementazioni di EF, che erano intenzionali - volevo evitare qualsiasi effetto/preconcetto negativo dalla mia effettiva implementazione (per non parlare del fatto che è cambiato un po 'mentre l'ho manipolato!) In modo che potessi essere in grado per avere consigli su come configurarlo fin dall'inizio. Stessa storia con le mie query di esempio, anche se immagino che il mio caso d'uso sia simile a questo: "1) Post creato con alcuni tag iniziali 2) I tag del post vengono modificati, alcuni eliminati, altri aggiunti 3) Il post viene salvato." – Xcelled194

+0

Quindi immagino che tu abbia familiarità con Contesto e cose del genere. Dal momento che hai alcuni dati in SQL. Usa LINQ per interrogare uno di loro. Se restituisce ancora 'null' potrebbe esserci qualcosa di sbagliato nelle tue query. – Tico

risposta

2

Provare anche a definire la relazione dal lato Tag, specificando ogni Tag relativo a un singolo Post ed è necessario.

aggiunge una proprietà di navigazione richiesto per Post in Tag:

public class Tag 
{ 
    // you need an ID 
    public int Id { get; set; } 

    public string Text { get; set; } 

    [Required] 
    public virtual Post Post { get; set; } 
} 

In alternativa, se proprio non si vuole aggiungere la proprietà di navigazione, è possibile utilizzare l'API Fluent:

modelBuilder.Entity<Post>().HasMany(p => p.Tags).WithRequired(); 
+0

Di solito aggiungo un 'Id' per la proprietà di navigazione. – Tico

+0

Intendevo che hai bisogno di un campo ID della chiave primaria per le tue entità; Supponendo che li abbia lasciati fuori per brevità – Moho

+0

Il '[Required]' DataAnnotation viene utilizzato per creare una relazione richiesta. Quello che intendevo era "public virtual Post Post {get; impostato; } 'e anche una proprietà come:' public int PostId {get; impostato; } '. Quando cerco un oggetto ho solo l'ID. Se cerco un 'Post' restituirà' null' – Tico

0

Questa probabilmente è la negromanzia del thread, ma non ho il rappresentante per commentare. Non farebbe quanto segue ciò che ti serve?

public class Tag 
{ 
    [Key, Column(Order=1), DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    public string Text { get; set; } 
    // Possibly other properties here 

    public int PostId { get; set; } 

    [ForeignKey("PostId")] 
    public virtual Post Post { get; set; } 

} 

postID viene caricato dal database, poi utilizzato come chiave esterna (tramite l'annotazione) nella classe Post. Il post è virtuale, nient'altro è. Probabilmente potresti anche andare con l'annotazione di base [Chiave].

+0

EF identifica automaticamente una proprietà denominata "ID" come identificativo univoco per una classe, quindi si sta diventando ridondanti. Inoltre, l'API Fluent sembra essere migliore (più affidabile) nella descrizione delle relazioni rispetto alle decorazioni sulle proprietà. Inoltre, la definizione delle relazioni in DbContext (così come il resto della descrizione della persistenza negli altri file del livello di accesso ai dati) consente di spostarsi da EF in un secondo momento con solo alcune modifiche. –

Problemi correlati