I have simple project to show the problem, I want to connect ICollection<Post>
with view View_BlogPosts
. This is just simplified scenario, in real live i need to connect entity with big View with many columns from different tables.
The most interesting part of code is: OnModelCreating(ModelBuilder modelBuilder)
where there is configuration View with Entity: Post
(One Blog to Many Posts). But its not working now, this line of code: var test = db.BlogWithPosts.ToList();
returns empty collection of Posts.
How to fix this?
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace Samples
{
public class Program
{
private static void Main()
{
SetupDatabase();
using (var db = new BloggingContext())
{
var test = db.BlogWithPosts.ToList();
}
}
private static void SetupDatabase()
{
using (var db = new BloggingContext())
{
if (db.Database.EnsureCreated())
{
db.Blogs.Add(
new Blog
{
Name = "Fish Blog",
Url = "http://sample.com/blogs/fish",
Posts = new List<Post>
{
new Post { Title = "Fish care 101" },
new Post { Title = "Caring for tropical fish" },
new Post { Title = "Types of ornamental fish" }
}
});
db.Blogs.Add(
new Blog
{
Name = "Cats Blog",
Url = "http://sample.com/blogs/cats",
Posts = new List<Post>
{
new Post { Title = "Cat care 101" },
new Post { Title = "Caring for tropical cats" },
new Post { Title = "Types of ornamental cats" }
}
});
db.Blogs.Add(
new Blog
{
Name = "Catfish Blog",
Url = "http://sample.com/blogs/catfish",
Posts = new List<Post>
{
new Post { Title = "Catfish care 101" }, new Post { Title = "History of the catfish name" }
}
});
db.SaveChanges();
db.Database.ExecuteSqlRaw(
@"CREATE VIEW View_BlogPosts AS
SELECT b.Name , b.BlogId, b.Url FROM Blogs b");
}
}
}
}
public class BloggingContext : DbContext
{
private static readonly ILoggerFactory _loggerFactory
= LoggerFactory.Create(
builder => builder.AddConsole().AddFilter((c, l) => l == LogLevel.Information && !c.EndsWith("Connection")));
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<BlogWithPosts> BlogWithPosts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
// @"Server=(localdb)\mssqllocaldb;Database=Sample.KeylessEntityTypes;Trusted_Connection=True;ConnectRetryCount=0;")
@"Server=.\SQLEXPRESS;Database=test_view;Trusted_Connection=True;")
.UseLoggerFactory(_loggerFactory);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogWithPosts>(eb =>
{
//eb.HasNoKey();
eb.ToView("View_BlogPosts");
eb.HasKey(bwp => bwp.BlogId);
eb.Property(v => v.BlogName).HasColumnName("Name");
eb
.HasMany(bwp => bwp.Posts)
.WithOne()
.HasForeignKey(p => p.BlogId);
});
}
}
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
}
public class BlogWithPosts
{
public int BlogId { get; set; }
public string BlogName { get; set; }
public ICollection<Post> Posts { get; set; } = new List<Post>();
}
}
EDIT:
Thanks @Neil W for answer:
It is good point but after var test = db.BlogWithPosts.Include(bwp => bwp.Posts).ToList();
there is still no Posts.
I have checked Database after run program and in Post table I find out, that there is second Id added: BlogId1
I have filled BlogId
column same as BlogId1
like this: and posts appeared
But how to set configuration that second id: BlogId1
will not appear.
You need to ask for the related entities when accessing the context, using Include:
var test = db.BlogWithPosts.Include(bwp => bwp.Posts).ToList();
Thanks for all answers and comments. As @atiyar point there should be explicitly relation between Post
and Blog
which stops creating BlogId1
column. So working example is like below:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace Samples
{
public class Program
{
private static void Main()
{
SetupDatabase();
using (var db = new BloggingContext())
{
var test = db.BlogWithPosts.Include(bp => bp.Posts).ToList();
}
}
private static void SetupDatabase()
{
using (var db = new BloggingContext())
{
if (db.Database.EnsureCreated())
{
db.Blogs.Add(
new Blog
{
Name = "Fish Blog",
Url = "http://sample.com/blogs/fish",
Posts = new List<Post>
{
new Post { Title = "Fish care 101" },
new Post { Title = "Caring for tropical fish" },
new Post { Title = "Types of ornamental fish" }
}
});
db.Blogs.Add(
new Blog
{
Name = "Cats Blog",
Url = "http://sample.com/blogs/cats",
Posts = new List<Post>
{
new Post { Title = "Cat care 101" },
new Post { Title = "Caring for tropical cats" },
new Post { Title = "Types of ornamental cats" }
}
});
db.Blogs.Add(
new Blog
{
Name = "Catfish Blog",
Url = "http://sample.com/blogs/catfish",
Posts = new List<Post>
{
new Post { Title = "Catfish care 101" }, new Post { Title = "History of the catfish name" }
}
});
db.SaveChanges();
db.Database.ExecuteSqlRaw(
@"CREATE VIEW View_BlogPosts AS
SELECT b.Name , b.BlogId, b.Url FROM Blogs b");
}
}
}
}
public class BloggingContext : DbContext
{
private static readonly ILoggerFactory _loggerFactory
= LoggerFactory.Create(
builder => builder.AddConsole().AddFilter((c, l) => l == LogLevel.Information && !c.EndsWith("Connection")));
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<BlogWithPosts> BlogWithPosts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
// @"Server=(localdb)\mssqllocaldb;Database=Sample.KeylessEntityTypes;Trusted_Connection=True;ConnectRetryCount=0;")
@"Server=.\SQLEXPRESS;Database=test_view;Trusted_Connection=True;")
.UseLoggerFactory(_loggerFactory);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogWithPosts>(eb =>
{
//eb.HasNoKey();
eb.ToView("View_BlogPosts");
eb.HasKey(bwp => bwp.BlogId);
eb.Property(v => v.BlogName).HasColumnName("Name");
eb
.HasMany(bwp => bwp.Posts)
.WithOne()
.HasForeignKey(p => p.BlogId);
});
modelBuilder.Entity<Blog>(blog =>
{
blog.HasMany(bwp => bwp.Posts)
.WithOne(b => b.Blog)
.HasForeignKey(p => p.BlogId);
});
}
}
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
public class BlogWithPosts
{
public int BlogId { get; set; }
public string BlogName { get; set; }
public ICollection<Post> Posts { get; set; } = new List<Post>();
}
}
What is important this example was tested on EF Core 5.0.2
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.