Can anyone write mini-guide which explains how to work with collections in EF?
For example I have following models:
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; }
}
And context class:
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);
}
}
What do I need to write in OnModelCreating method so that I can use Posts.Add and etc. everywhere in my code?
Here are my tips for working with navigation properties in Entity Framework Core.
Tip 1: Initialize collections
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; }
}
Tip 2: Build using the HasOne
and WithMany
or HasMany
and WithOne
methods
protected override void OnModelCreating(ModelBuilder model)
{
model.Entity<Post>()
.HasMany(p => p.Comments).WithOne(c => c.Post)
.HasForeignKey(c => c.PostId);
}
Tip 3: Eagerly load the collection
var posts = db.Posts.Include(p => p.Comments);
Tip 4: Explicitly load if you didn't eagerly
db.Comments.Where(c => c.PostId == post.Id).Load();
It seems that Comments
navigation property does not works properly. Try to provide to BlogPost
model the actual referencig field to PostComment
table. Also rename the navigation property in PostComments for the EF naming compliance.
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; }
}
If this neither works you have to define manually your relationship, but before help in this, you'd better provide the schema of this two tables in your db.
UPDATE 01:
First tip:
You are using singular named tables. This is not compliant to EF naming convention. Pluralization has to be turned off. Just put this line in OnModelCreating
method.
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
Second tip: My previous advice was totally wrong do not consider it anymore, just use your old models schema. Now, assuming a one-to-many relationship between comment and 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);
}
For more INFOs :
EF one-to-many relationship tutorial