using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public abstract class Model
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public CustomDbContext _ctx { get; set; }
public class Post : Model
_map = new HashSet<PostTag>();
protected virtual ICollection<PostTag> _map { get; set; }
public virtual ICollection<Foo> foos { get; set; }
public void Check(bool flag)
public static Post Load(CustomDbContext ctx)
return ctx.posts.Include(p => p._map).Include(p => p.foos).First();
public void Add(PostTag postTag)
public class PostTag : Model
public virtual Post post { get; set; }
public virtual Tag tag { get; set; }
_map = new HashSet<PostTag>();
protected virtual ICollection<PostTag> _map { get; set; }
public class CustomDbContext : DbContext
public CustomDbContext(DbContextOptions options)
protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<Post>().HasMany(typeof(PostTag), "_map").WithOne();
modelBuilder.Entity<Tag>().HasMany(typeof(PostTag), "_map").WithOne();
public DbSet<Post> posts { get; set; }
public DbSet<Tag> tags { get; set; }
protected IServiceProvider _serviceProvider;
using (var ctx = new CustomDbContext(GetDbContextOptions()))
Assert.Equal(4, ctx.Model.GetEntityTypes().Count());
ctx.posts.AddRange(new List<Post>() {new Post(), new Post(), new Post(), new Post()});
ctx.tags.AddRange(new List<Tag>() {new Tag(), new Tag(), new Tag()});
Assert.Equal(4, ctx.posts.Count());
Assert.Equal(3, ctx.tags.Count());
foreach (var tag in ctx.tags)
foreach (var post in ctx.posts)
PostTag p = new PostTag {post = post, tag = tag};
var firstPost = ctx.posts.First();
if (firstPost.foos == null)
firstPost.foos = new List<Foo>();
firstPost.foos.Add(new Foo());
using (var newCtx = new CustomDbContext(GetDbContextOptions()))
var loadedPost = newCtx.posts.First();
Assert.NotNull(loadedPost);
Assert.Empty(loadedPost.foos);
var loadedPostWithInclude = Post.Load(newCtx);
Assert.NotNull(loadedPostWithInclude);
Assert.NotEmpty(loadedPostWithInclude.foos);
loadedPostWithInclude.Check(true);
private static DbContextOptions<CustomDbContext> GetDbContextOptions()
return new DbContextOptionsBuilder<CustomDbContext>().UseInMemoryDatabase("Scratch")
.UseInternalServiceProvider(new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider()).Options;