2015-05-17 10 views
9

Qualcuno può scrivere una mini-guida che spiega come lavorare con le raccolte in EF?Come lavorare con le raccolte

Ad esempio ho seguenti modelli:

public class BlogPost 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public string Content { get; set; } 
    public DateTime DateTime { get; set; } 
    public List<PostComment> Comments { get; set; } 
} 

public class PostComment 
{ 
    public int Id { get; set; } 
    public BlogPost ParentPost { get; set; } 
    public string Content { get; set; } 
    public DateTime DateTime { get; set; } 
} 

e Classe contesto:

public class PostContext : DbContext 
{ 
    public DbSet<BlogPost> Posts { get; set; } 
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 
    { 
     optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Posts;Trusted_Connection=True;MultipleActiveResultSets=true"); 

    } 
    protected override void OnModelCreating(ModelBuilder builder) 
    { 
     base.OnModelCreating(builder); 

    } 
} 

cosa ho bisogno di scrivere in modo OnModelCreating in modo che posso usare Posts.Add ed ecc ovunque nel mio codice?

+0

Non si dovrebbe scrivere in quel metodo per aggiungere entità ai tuoi dbset. Stai sperimentando problemi? –

+0

@FabioCarello Ho il problema "Riferimento oggetto non impostato su un'istanza di un oggetto.", Quando provo a ottenere post.Comments.Count (alcuni post con commenti sono stati aggiunti prima). Ecco perché ho fatto la domanda. – neonhash

+0

"mini-guida che spiega come lavorare con le collezioni in EF?" Troppo ampio Questa particolare area sarà simile a EF6. –

risposta

17

Ecco i miei consigli per lavorare con le proprietà di navigazione in Entity Framework Core.

Suggerimento 1: inizializzazione collezioni

class Post 
{ 
    public int Id { get; set; } 

    // Initialize to prevent NullReferenceException 
    public ICollection<Comment> Comments { get; } = new List<Comment>(); 
} 

class Comment 
{ 
    public int Id { get; set; } 
    public string User { get; set; } 

    public int PostId { get; set; } 
    public Post Post { get; set; }   
} 

Suggerimento 2: Corporatura utilizzando i metodi HasOne e WithMany o HasMany e WithOne

protected override void OnModelCreating(ModelBuilder model) 
{ 
    model.Entity<Post>() 
     .HasMany(p => p.Comments).WithOne(c => c.Post) 
     .HasForeignKey(c => c.PostId); 
} 

Suggerimento 3: Avidamente caricare la collezione

var posts = db.Posts.Include(p => p.Comments); 

Suggerimento 4: esplicitamente caricare se non l'avete fatto con entusiasmo

db.Comments.Where(c => c.PostId == post.Id).Load(); 
+0

Grazie! Per me funziona. Ma ora ho una nuova domanda, cosa devo fare con le raccolte di tipi standard, come "Lista "? Non riesco a fare InverseReference, perché la stringa non ha proprietà come "c.Post" nel tuo esempio. Per risolvere questo ho scritto questo codice: http://pastebin.com/3w7xCQ2k Ma è giusto così? Come posso renderlo più semplice? Voglio davvero usare smth come questo "public ICollection Tags {get; set;} = new List ();" – neonhash

+0

@neonhash Attualmente non sono supportati. Devi avvolgerli all'interno di un tipo di entità. Per esempio.'class StringValue {string Value {get; impostato; }} ' – bricelam

+0

Solo una nota per dire grazie, questo è l'esempio più chiaro di come ottenere questo lavoro che ho trovato. –

1

Sembra che la proprietà di navigazione Comments non funzioni correttamente. Prova a fornire al modello BlogPost il campo referencig effettivo alla tabella PostComment. Rinominare anche la proprietà di navigazione in PostComments per la conformità ai nomi EF.

public class BlogPost 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public string Content { get; set; } 
    public DateTime DateTime { get; set; } 

    public int PosCommentId {get; set; } 
    public List<PostComment> PostComments { get; set; } 
} 

Se questo non funziona è necessario definire manualmente il vostro rapporto, ma prima di aiuto in questo, è meglio fornire lo schema di questi due tabelle del db.

UPDATE 01:

Primo suggerimento: Si utilizza tabelle denominate singolari. Questo non è conforme alla convenzione di denominazione EF. La pluralizzazione deve essere disattivata. Basta inserire questa riga nel metodo OnModelCreating.

modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 

Seconda punta: Il mio consiglio precedente era totalmente sbagliato non considerano più, basta usare lo schema vecchi modelli. Ora, ipotizzando una relazione uno-a-molti tra commento e post:

protected override void OnModelCreating(ModelBuilder builder) 
{ 
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 
    modelBuilder.Entity<PostComment>().HasRequired<BlogPost>(c => c.ParentPost) 
      .WithMany(p => p.Comments); 

    base.OnModelCreating(builder); 

} 

Per maggiori informazioni:

EF one-to-many relationship tutorial

Relationship and navigation properties

Configuring Relationships with the Fluent API

+0

Non ha funzionato per me. Ho aggiunto commenti a DbSet e ho usato questo codice: http://pastebin.com/5vFcJrZu, funziona, ma è giusto? – neonhash

+0

Stai provando a impostare manualmente la relazione? Non penso sia definitivamente una buona idea. Potresti pubblicare lo schema db per queste due tabelle? –

+0

Sì, potrei: pastebin.com/Ti6dUjEv – neonhash

0

Giusto per aggiungere sulle risposte da @FabioCarello e @bricela, mi consiglia di utilizzare la parola chiave virtuale su proprietà di navigazione:

public virtual ICollection<Comment> { get; set; } 

Questo permetterà pigro Caricamento in corso, il che significa che le collezioni/i riferimenti verranno caricati solo alla prima chiamata e non durante il primo recupero dei dati. Ciò è molto utile per evitare, ad esempio, lo stack overflow su riferimenti ricorsivi.

No perfetto è necessario per semplici uno-a-molti relazioni come la vostra, a meno che non hai bisogno di comportamenti non standard come richiede esplicitamente riferimenti non annullabili.

Si può anche fare uso di espliciti chiavi esterne che è utile in modo da non dover caricare il genitore quando hai solo bisogno il suo Id:

public class PostComment 
{ 
    public int Id { get; set; } 
    public BlogPost ParentPost { get; set; } 
    // // 
    public int? ParentPostId { get; set; } 
    // // 
    public string Content { get; set; } 
    public DateTime DateTime { get; set; } 
} 
+0

Questo è stato probabilmente downvoted (non da me) perché questa domanda riguarda EF7, che non supporta attualmente pigro carico] (https://github.com/aspnet/EntityFramework/issues/3312). – Matt