Ответ 1
Глядя на это, я подозреваю, что проблема может быть вызвана тем фактом, что вы сопоставляете одно и то же отношение дважды. И вы сопоставляете его в другом порядке.
Я сделал простой тест, где я сначала сопоставил взаимосвязь один раз:
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
var p = new Parent();
var c = new Child();
using (var db = new Context())
{
db.Parents.Add(new Parent());
db.Parents.Add(p);
db.Children.Add(c);
db.SaveChanges();
}
using (var db = new Context())
{
var reloadedP = db.Parents.Find(p.ParentId);
var reloadedC = db.Children.Find(c.ChildId);
reloadedP.Children = new List<Child>();
reloadedP.Children.Add(reloadedC);
db.SaveChanges();
}
using (var db = new Context())
{
Console.WriteLine(db.Children.Count());
Console.WriteLine(db.Children.Where(ch => ch.ChildId == c.ChildId).Select(ch => ch.Parents.Count).First());
Console.WriteLine(db.Parents.Where(pa => pa.ParentId == p.ParentId).Select(pa => pa.Children.Count).First());
}
}
}
public class Parent
{
public int ParentId { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public int ChildId { get; set; }
public ICollection<Parent> Parents { get; set; }
}
public class Context : DbContext
{
public Context() : base("data source=Mikael-PC;Integrated Security=SSPI;Initial Catalog=EFTest")
{
}
public IDbSet<Child> Children { get; set; }
public IDbSet<Parent> Parents { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Child>()
.HasMany(x => x.Parents)
.WithMany(x => x.Children)
.Map(c =>
{
c.MapLeftKey("ChildId");
c.MapRightKey("ParentId");
c.ToTable("ChildToParentMapping");
});
}
}
И затем я изменил OnModelCreating как:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Child>()
.HasMany(x => x.Parents)
.WithMany(x => x.Children)
.Map(c =>
{
c.MapLeftKey("ChildId");
c.MapRightKey("ParentId");
c.ToTable("ChildToParentMapping");
});
modelBuilder.Entity<Parent>()
.HasMany(x => x.Children)
.WithMany(x => x.Parents)
.Map(c =>
{
c.MapLeftKey("ParentId");
c.MapRightKey("ChildId");
c.ToTable("ChildToParentMapping");
});
}
Что я нашел и подозревал, что первый запуск генерирует этот sql:
exec sp_executesql N'insert [dbo].[ChildToParentMapping]([ChildId], [ParentId])
values (@0, @1)
',N'@0 int,@1 int',@0=1,@1=2
В отличие от второго, который генерирует:
exec sp_executesql N'insert [dbo].[ChildToParentMapping]([ParentId], [ChildId])
values (@0, @1)
',N'@0 int,@1 int',@0=1,@1=2
Вы видите, что значения перевернуты? Здесь он фактически учитывает столбец ChildId как ParentId. Теперь это не сбой для меня, но я позволил EF создать базу данных, что означает, что он, вероятно, просто переключит имена столбцов, и если бы я посмотрел на внешние ключи, они тоже были бы переключены. Если вы создали базу данных вручную, что, вероятно, не будет.
Итак, короче: вы не равны, и я ожидаю, что один из них будет использован, и что, вероятно, он ошибается. В предыдущих версиях я думаю, что EF выбрал их в другом порядке.
UPDATE: Мне немного любопытно узнать о внешних ключах и проверить sql.
Из первого кода:
ALTER TABLE [dbo].[ChildToParentMapping] ADD CONSTRAINT [FK_dbo.ChildToParentMapping_dbo.Children_ChildId] FOREIGN KEY ([ChildId]) REFERENCES [dbo].[Children] ([ChildId]) ON DELETE CASCADE
И из второго кода:
ALTER TABLE [dbo].[ChildToParentMapping] ADD CONSTRAINT [FK_dbo.ChildToParentMapping_dbo.Children_ParentId] FOREIGN KEY ([ParentId]) REFERENCES [dbo].[Children] ([ChildId]) ON DELETE CASCADE
Теперь это не приятно. ParentId сопоставлен с детьми, конечно, не то, что мы хотим.
Итак, второе неправильное отображение? Не совсем потому, что смотрите, что случилось, когда я удалил первый:
ALTER TABLE [dbo].[ChildToParentMapping] ADD CONSTRAINT [FK_dbo.ChildToParentMapping_dbo.Parents_ParentId] FOREIGN KEY ([ParentId]) REFERENCES [dbo].[Parents] ([ParentId]) ON DELETE CASCADE
Как-то с двумя сопоставлениями, кажется, все испортилось. Ошибка или нет. Я не знаю.