Skip to content

Instantly share code, notes, and snippets.

@synercoder
Last active April 4, 2018 09:43
Show Gist options
  • Save synercoder/ca54951d01b75bf07a06c960405e5ec3 to your computer and use it in GitHub Desktop.
Save synercoder/ca54951d01b75bf07a06c960405e5ec3 to your computer and use it in GitHub Desktop.
ManyToManyBug
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2009
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManyToManyBug", "ManyToManyBug\ManyToManyBug.csproj", "{0660B97F-160A-4FC4-96FD-9F1BBDF086CE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0660B97F-160A-4FC4-96FD-9F1BBDF086CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0660B97F-160A-4FC4-96FD-9F1BBDF086CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0660B97F-160A-4FC4-96FD-9F1BBDF086CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0660B97F-160A-4FC4-96FD-9F1BBDF086CE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {64732E80-92CA-42F5-9447-C0E25ACC9816}
EndGlobalSection
EndGlobal
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0-preview3-32116" />
</ItemGroup>
</Project>
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ManyToManyBug
{
class Program
{
static void Main(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<ManyContext>();
optionsBuilder.UseSqlServer("Server=localhost\\SQLEXPRESS;Database=ManyToManyTest;Trusted_Connection=True;MultipleActiveResultSets=true");
// normal, is bugged
RecreateDatabase(optionsBuilder.Options);
FillFoosAndBars(optionsBuilder.Options);
AddSixManyToManyRelationsWithoutState(optionsBuilder.Options);
CheckSixRelations(optionsBuilder.Options);
// workaround
RecreateDatabase(optionsBuilder.Options);
FillFoosAndBars(optionsBuilder.Options);
AddSixManyToManyRelationsWithState(optionsBuilder.Options);
CheckSixRelations(optionsBuilder.Options);
Console.WriteLine("Done...");
Console.ReadLine();
}
static void RecreateDatabase(DbContextOptions<ManyContext> options)
{
Console.WriteLine("Recreating database...");
using (var context = new ManyContext(options))
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
}
}
static void FillFoosAndBars(DbContextOptions<ManyContext> options)
{
Console.WriteLine("Adding foos and bars...");
using (var context = new ManyContext(options))
{
context.Foos.Add(new Foo() { FooName = "foo1" });
context.Foos.Add(new Foo() { FooName = "foo2" });
context.Foos.Add(new Foo() { FooName = "foo3" });
context.Bars.Add(new Bar() { BarName = "bar1" });
context.Bars.Add(new Bar() { BarName = "bar2" });
context.Bars.Add(new Bar() { BarName = "bar3" });
context.SaveChanges();
}
}
static void AddSixManyToManyRelationsWithoutState(DbContextOptions<ManyContext> options)
{
Console.WriteLine("Adding relationships using DbSet<>.Add");
using (var context = new ManyContext(options))
{
var foo1 = context.Foos.Single(f => f.FooName == "foo1");
var foo2 = context.Foos.Single(f => f.FooName == "foo2");
var foo3 = context.Foos.Single(f => f.FooName == "foo3");
var bar1 = context.Bars.Single(f => f.BarName == "bar1");
var bar2 = context.Bars.Single(f => f.BarName == "bar2");
var bar3 = context.Bars.Single(f => f.BarName == "bar3");
context.FooBars.Add(new FooBar() { Foo = foo1, Bar = bar1 });
context.FooBars.Add(new FooBar() { Foo = foo1, Bar = bar2 });
context.FooBars.Add(new FooBar() { Foo = foo1, Bar = bar3 });
context.FooBars.Add(new FooBar() { Foo = foo2, Bar = bar3 });
context.FooBars.Add(new FooBar() { Foo = foo3, Bar = bar1 });
context.FooBars.Add(new FooBar() { Foo = foo3, Bar = bar2 });
context.SaveChanges();
}
}
static void AddSixManyToManyRelationsWithState(DbContextOptions<ManyContext> options)
{
Console.WriteLine("Adding relationships using DbSet<>.Add(...).State = EntityState.Added");
using (var context = new ManyContext(options))
{
var foo1 = context.Foos.Single(f => f.FooName == "foo1");
var foo2 = context.Foos.Single(f => f.FooName == "foo2");
var foo3 = context.Foos.Single(f => f.FooName == "foo3");
var bar1 = context.Bars.Single(f => f.BarName == "bar1");
var bar2 = context.Bars.Single(f => f.BarName == "bar2");
var bar3 = context.Bars.Single(f => f.BarName == "bar3");
context.FooBars.Add(new FooBar() { Foo = foo1, Bar = bar1 }).State = EntityState.Added;
context.FooBars.Add(new FooBar() { Foo = foo1, Bar = bar2 }).State = EntityState.Added;
context.FooBars.Add(new FooBar() { Foo = foo1, Bar = bar3 }).State = EntityState.Added;
context.FooBars.Add(new FooBar() { Foo = foo2, Bar = bar3 }).State = EntityState.Added;
context.FooBars.Add(new FooBar() { Foo = foo3, Bar = bar1 }).State = EntityState.Added;
context.FooBars.Add(new FooBar() { Foo = foo3, Bar = bar2 }).State = EntityState.Added;
context.SaveChanges();
}
}
static void CheckSixRelations(DbContextOptions<ManyContext> options)
{
Console.WriteLine("Checking relationship count...");
using (var context = new ManyContext(options))
{
var count = context.FooBars.Count();
if(count != 6)
{
Console.WriteLine("OMG OMG OMG!! BUG BUG BUG! FIRE AND BRIMSTONE!");
Console.WriteLine($"Count is {count} instead of 6.");
}
else
{
Console.WriteLine("Everything is as it should be.");
}
}
Console.WriteLine();
}
}
public class ManyContext : DbContext
{
public ManyContext(DbContextOptions<ManyContext> options)
: base(options)
{ }
public DbSet<Foo> Foos { get; set; }
public DbSet<Bar> Bars { get; set; }
public DbSet<FooBar> FooBars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Key is a shadow property
modelBuilder.Entity<Foo>().Property(typeof(Guid), "Id").ValueGeneratedOnAdd();
modelBuilder.Entity<Foo>().HasKey("Id");
modelBuilder.Entity<Foo>().HasIndex(x => x.FooName).IsUnique();
// Key is a shadow property
modelBuilder.Entity<Bar>().Property(typeof(Guid), "Id").ValueGeneratedOnAdd();
modelBuilder.Entity<Bar>().HasKey("Id");
modelBuilder.Entity<Bar>().HasIndex(x => x.BarName).IsUnique();
// Keys are shadow properties
modelBuilder.Entity<FooBar>().Property(typeof(Guid), "Foo_Id");
modelBuilder.Entity<FooBar>().HasOne(x => x.Foo).WithMany(x => x.FooBars).HasForeignKey("Foo_Id");
modelBuilder.Entity<FooBar>().Property(typeof(Guid), "Bar_Id");
modelBuilder.Entity<FooBar>().HasOne(x => x.Bar).WithMany(x => x.FooBars).HasForeignKey("Bar_Id");
modelBuilder.Entity<FooBar>().HasKey("Foo_Id", "Bar_Id");
}
}
public class FooBar
{
public Foo Foo { get; set; }
public Bar Bar { get; set; }
}
public class Foo
{
public string FooName { get; set; }
public ICollection<FooBar> FooBars { get; set; }
}
public class Bar
{
public string BarName { get; set; }
public ICollection<FooBar> FooBars { get; set; }
}
}
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="MyGetAspNetCore" value="https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json" />
<add key="MyGetDotNetCore" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
</packageSources>
</configuration>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment