entity framework5升级后,多对多关系左右键被翻转
我有一些代码可以在代码中保存多对多的关系。 它与Entity Framework 4.1一起运行良好,但在更新到Entity Framework 5后,它失败了。
我收到以下错误:
INSERT语句与FOREIGN KEY约束“FK_WebUserFavouriteEvent_Event”冲突。 冲突发生在数据库“MainEvents”,表“dbo.Event”,列“Id”中。
我正在使用POCO实体和自定义映射。 标准字段和多对一关系映射似乎工作正常。
UPDATE
好的,所以我安装了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应该是14,而EventId 应该是1820 ,而不是像现在这样。
我查看了映射代码,我99%我已经正确设置了它。 有关详细信息,请参阅Entity Framework Fluent API – 关系MSDN文章 。
注意:我还发现这不仅限于保存,SELECT也被破坏了。
这是所有相关代码:
服务层
public void AddFavEvent(WebUser webUser, Event @event) { webUser.FavouriteEvents.Add(@event); _webUserRepo.Update(webUser); }
知识库
public void Update(params T[] entities) where T : DbTable { foreach (var entity in entities) { entity.UpdatedOn = DateTime.UtcNow; } _dbContext.SaveChanges(); }
注意:我正在使用每个请求方法1个DataContext,因此webUser
和@event
将从与@event
的上下文相同的上下文中_webUserRepo
。
实体 (不要担心DbTable的东西)
public class Event : DbTable { //BLAH public virtual ICollection FavouriteOf { get; set; } //BLAH } public class WebUser : DbTable { //BLAH public virtual ICollection FavouriteEvents { get; set; } //BLAH }
映射
public class EventMapping : DbTableMapping { 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 { 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()); 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(); 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 Children { get; set; } } public class Child { public int ChildId { get; set; } public ICollection Parents { get; set; } } public class Context : DbContext { public Context() : base("data source=Mikael-PC;Integrated Security=SSPI;Initial Catalog=EFTest") { } public IDbSet Children { get; set; } public IDbSet Parents { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity() .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() .HasMany(x => x.Parents) .WithMany(x => x.Children) .Map(c => { c.MapLeftKey("ChildId"); c.MapRightKey("ParentId"); c.ToTable("ChildToParentMapping"); }); modelBuilder.Entity() .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肯定不是我们想要的。
那么第二个映射错了吗? 不是真的因为看到我删除第一个时发生的事情:
ALTER TABLE [dbo].[ChildToParentMapping] ADD CONSTRAINT [FK_dbo.ChildToParentMapping_dbo.Parents_ParentId] FOREIGN KEY ([ParentId]) REFERENCES [dbo].[Parents] ([ParentId]) ON DELETE CASCADE
不知何故有两个映射似乎搞砸了。 我有什么不知道的错误。
我可以确认这是EF5中的一个错误,虽然我仍然不确定它在4.3.1中是如何工作的。
问题是我们没有正确地将LeftKey / RightKey调用与其对应的导航属性相关联。
我将在CodePlex项目网站上提交EF6错误。
要解决这个问题,我想你需要:
- 仅从一侧配置关联。 要么,
- 在两种配置中将LeftKey / RightKey列名称切换为相同。
抱歉给你带来不便。
更新 :这是错误 。
上述就是C#学习教程:entity framework5升级后,多对多关系左右键被翻转分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/953139.html