Cha*_*ino 13 c# sql-server entity-framework entity-framework-5
我有一些代码可以在代码中保存多对多的关系.它与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
Run Code Online (Sandbox Code Playgroud)
意思是:
WebUserId = @0 = 1820
EventId = @1 = 14
Run Code Online (Sandbox Code Playgroud)
有趣的是,EF5似乎已经翻转了外键 ...... WebUserId应该是14,而EventId 应该是1820,而不是像现在这样.
我查看了映射代码,我99%我已经正确设置了它.有关详细信息,请参阅实体框架Fluent API - 关系MSDN文章.
注意:我还发现这不仅限于保存,SELECT也被破坏.
这是所有相关代码:
服务层
public void AddFavEvent(WebUser webUser, Event @event)
{
webUser.FavouriteEvents.Add(@event);
_webUserRepo.Update(webUser);
}
Run Code Online (Sandbox Code Playgroud)
知识库
public void Update<T>(params T[] entities)
where T : DbTable
{
foreach (var entity in entities)
{
entity.UpdatedOn = DateTime.UtcNow;
}
_dbContext.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
注意:我正在使用每个请求方法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
}
Run Code Online (Sandbox Code Playgroud)
映射
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");
});
}
}
Run Code Online (Sandbox Code Playgroud)
Mik*_*son 13
看着这个,我怀疑这个问题可能是因为你将同一个关系映射两次.然后以不同的顺序映射它.
我做了一个简单的测试,我第一次映射关系:
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");
});
}
}
Run Code Online (Sandbox Code Playgroud)
然后我将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");
});
}
Run Code Online (Sandbox Code Playgroud)
我发现和怀疑的是第一次运行生成这个sql:
exec sp_executesql N'insert [dbo].[ChildToParentMapping]([ChildId], [ParentId])
values (@0, @1)
',N'@0 int,@1 int',@0=1,@1=2
Run Code Online (Sandbox Code Playgroud)
与产生的第二个相反:
exec sp_executesql N'insert [dbo].[ChildToParentMapping]([ParentId], [ChildId])
values (@0, @1)
',N'@0 int,@1 int',@0=1,@1=2
Run Code Online (Sandbox Code Playgroud)
你看到价值被翻转了吗?这里它实际上将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
Run Code Online (Sandbox Code Playgroud)
从第二个代码:
ALTER TABLE [dbo].[ChildToParentMapping] ADD CONSTRAINT [FK_dbo.ChildToParentMapping_dbo.Children_ParentId] FOREIGN KEY ([ParentId]) REFERENCES [dbo].[Children] ([ChildId]) ON DELETE CASCADE
Run Code Online (Sandbox Code Playgroud)
现在这不好.针对儿童映射的ParentId肯定不是我们想要的.
那么第二个映射错了吗?不是真的因为看到我删除第一个时发生的事情:
ALTER TABLE [dbo].[ChildToParentMapping] ADD CONSTRAINT [FK_dbo.ChildToParentMapping_dbo.Parents_ParentId] FOREIGN KEY ([ParentId]) REFERENCES [dbo].[Parents] ([ParentId]) ON DELETE CASCADE
Run Code Online (Sandbox Code Playgroud)
不知何故有两个映射似乎搞砸了.不管是不是我不知道.
| 归档时间: |
|
| 查看次数: |
5552 次 |
| 最近记录: |