gpt4 book ai didi

c# - Entity Framework 5 升级后多对多关系左右键翻转

转载 作者:可可西里 更新时间:2023-11-01 08:06:39 24 4
gpt4 key购买 nike

我有一些代码可以在代码中保存多对多关系。它在 Entity Framework 4.1 上运行良好,但在更新到 Entity Framework 5 后,它失败了。

我收到以下错误:

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_WebUserFavouriteEvent_Event". The conflict occurred in database "MainEvents", table "dbo.Event", column 'Id'.

我正在使用带有自定义映射的 POCO 实体。标准字段和多对一关系映射似乎工作正常。

更新

好吧,我已经安装了 SQL Profiler,并且情节已经变厚了......

exec sp_executesql N'insert [dbo].[WebUserFavouriteEvent]([WebUserId], [EventId])
values (@0, @1)
',N'@0 int,@1 int',@0=1820,@1=14

这意味着:

WebUserId = @0 = 1820
EventId = @1 = 14

有趣的是,EF5 似乎翻转了外键...WebUserId 应该是 14EventId 应该是 1820,而不是像现在这样反过来。

我检查了映射代码,99% 的设置都正确无误。参见 Entity Framework Fluent API - Relationships MSDN article获取更多信息。

注意:我还发现这不仅限于保存,SELECT 也会损坏。

以下是所有相关代码:

服务层

public void AddFavEvent(WebUser webUser, Event @event)
{
webUser.FavouriteEvents.Add(@event);

_webUserRepo.Update(webUser);
}

存储库

public void Update<T>(params T[] entities)
where T : DbTable
{
foreach (var entity in entities)
{
entity.UpdatedOn = DateTime.UtcNow;
}

_dbContext.SaveChanges();
}

注意:我使用每个请求 1 个 DataContext 方法,因此 webUser@event 会从相同的上下文加载作为 _webUserRepo 中的那个。

实体(不用担心 DbTable 的东西)

public class Event : DbTable
{
//BLAH
public virtual ICollection<WebUser> FavouriteOf { get; set; }
//BLAH
}

public class WebUser : DbTable
{
//BLAH
public virtual ICollection<Event> FavouriteEvents { get; set; }
//BLAH
}

映射

public class EventMapping : DbTableMapping<Event>
{
public EventMapping()
{
ToTable("Event");
//BLAH
HasMany(x => x.FavouriteOf)
.WithMany(x => x.FavouriteEvents)
.Map(x =>
{
x.MapLeftKey("EventId");
x.MapRightKey("WebUserId");
x.ToTable("WebUserFavouriteEvent");
});
}
}

public class WebUserMapping : DbTableMapping<WebUser>
{
public WebUserMapping ()
{
HasMany(x => x.FavouriteEvents)
.WithMany(x => x.FavouriteOf)
.Map(m =>
{
m.MapLeftKey("WebUserId");
m.MapRightKey("EventId");
m.ToTable("WebUserFavouriteEvent");
});
}
}

最佳答案

看着这个,我怀疑问题可能是由于您将相同的关系映射了两次而引起的。并且您以不同的顺序映射它。

我做了一个简单的测试,我首先映射了一次关系:

    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 以不同的顺序拾取它们。

更新:对外键有点好奇,查了一下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 映射到 Children 肯定不是我们想要的。

那么第二个映射是不是错了?不是真的,因为看看我删除第一个时发生了什么:

ALTER TABLE [dbo].[ChildToParentMapping] ADD CONSTRAINT [FK_dbo.ChildToParentMapping_dbo.Parents_ParentId] FOREIGN KEY ([ParentId]) REFERENCES [dbo].[Parents] ([ParentId]) ON DELETE CASCADE

不知何故,有两个映射似乎把事情搞砸了。我不知道有没有错误。

关于c# - Entity Framework 5 升级后多对多关系左右键翻转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12192679/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com