【问题标题】:Entity-Framework: Create Many-To-Many-Relations实体框架:创建多对多关系
【发布时间】:2018-05-02 20:02:01
【问题描述】:

我们对应用程序使用“DB-First”方法,因为数据库在各种应用程序之间共享,所以它应该是“主”。 (MySQL)

我们有3个简单的表,负责Role-To-Permission的赋值,像这样:

Visual-Studio 模型设计器(在从数据库构建模型之后)完美地将其识别为“多对多”关系,甚至没有生成“Role_to_permission”-实体,因为没有进一步的属性作业)

到目前为止,我们在数据库中创建了这些条目,从而在应用程序中产生了预期的结果。 (访问映射)

目前我们正在开发一个接口,允许将“权限”分配给“角色”。在这里,我有点卡住了:

  • 如果此类关系具有其他属性(例如 requireddate),EMF 会为该关系创建一个自己的实体 - 假设 Permission_To_Role

然后,我可以使用以下代码“轻松”创建关系:

using (MyDb db = new MyDB()){
   Permission_To_Role ptr = new Permission_To_Role();
   ptr.PermissionId = 5;
   ptr.RoleId = 8;
   ptr.CreationDate = DateTime.Now();

   db.Permission_To_Role.Add(ptr);
   db.SaveChanges();
}

无论如何 - 在这种情况下 - 我们在映射上没有任何附加属性,因此 EF 框架避免了附加类。

我现在正在努力创建关系,但没有成功:

using (MyDB db = new MyDB())
{
    //Get ids.
    long permissionId = 2;
    long roleID = 5;

    Permission p = db.Permission.Find(permissionId);
    Role r = db.Role.Find(roleID);

    r.Permissions.Add(p);

    db.SaveChanges();
}

这总是会导致异常,我不知道为什么(ID 存在且正确)...

db.SaveChanges() 的例外情况:

类型异常 'System.Data.Entity.Infrastructure.DbUpdateException' 发生在 EntityFramework.dll 但未在用户代码中处理

附加信息:保存实体时出错 不要为它们的关系公开外键属性。这 EntityEntries 属性将返回 null,因为单个实体不能 被识别为异常的来源。异常处理 而通过将外键属性暴露在 您的实体类型。有关详细信息,请参阅 InnerException。

内部异常:

更新条目时出错。查看内部异常 了解详情。

内部内部异常:

您的 SQL 语法有错误;检查手册 对应于您的 MySQL 服务器版本,以便使用正确的语法 附近'(选择Permission_to_Role.PermissionId, Permission_to_Role.RoleId FROM' 在第 1 行

想法?


更新:

SHOW CREATE TABLE Permission_to_Role;

输出:

CREATE TABLE `Permission_to_Role` (
  `PermissionId` bigint(19) NOT NULL,
  `RoleId` bigint(19) NOT NULL,
  UNIQUE KEY `Permission_to_Role_unique` (`PermissionId`,`RoleId`),
  KEY `Permission_Mapping_idx` (`PermissionId`),
  KEY `Role_Mapping_idx` (`RoleId`),
  CONSTRAINT `Permission_Mapping` FOREIGN KEY (`PermissionId`) REFERENCES `permission` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `Role_Mapping` FOREIGN KEY (`RoleId`) REFERENCES `role` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8

更新2:

截至目前的 cmets:我启用了 EF 生成的查询的输出,并发现了这个魅力 - 这显然是一个格式错误的查询:

INSERT INTO 
  (SELECT 
    Permission_to_Role.PermissionId,
    Permission_to_Role.RoleId  
   FROM 
     Permission_to_Role AS Permission_to_Role
  )
  ( PermissionId, RoleId) VALUES ( 2, 1)

查询实际应该是:

INSERT INTO 
  Permission_To_Role
  ( PermissionId, RoleId) VALUES ( 2, 1)

所以,我认为这看起来像一个“错误”?如上所述:

无论如何 - 在这种情况下 - 我们在映射上没有任何附加属性,因此 EF 框架避免了附加类。

没有中间 Permission_To_Role 实体,因此似乎 EF 试图用查询替换这个 表名

  SELECT 
    Permission_to_Role.PermissionId,
    Permission_to_Role.RoleId  
   FROM 
     Permission_to_Role AS Permission_to_Role

即使在插入时...(也许这适用于 MsSQL 并且对于 MySQL 连接器来说是一个糟糕的实现?)

【问题讨论】:

  • @AussieJoe 有一个快速提示吗?
  • Entity Framework 正在执行的生成的 SQL 是什么?你检查过失败的 SQL 吗?
  • @AussieJoe 好吧,这仅适用于访问IQueryable - 但是在使用context 时发现了这个:context.Database.Log = Console.WriteLine;(我会马上回来更新)@987654324 @
  • 这是我猜的关键点:这对我来说似乎毫无意义(或者是更高技能的 SQL :P)INSERT INTO (SELECT Permission_to_Role.PermissionId, Permission_to_Role.RoleId FROM Permission_to_Role AS Permission_to_Role)( PermissionId, RoleId) VALUES ( 2, 1)

标签: c# mysql entity-framework


【解决方案1】:

我现在有点累,但终于开始工作了。

我不能 100% 确定真正的问题,因为我改变了很多东西 - 但以下“发现”是解决这个问题时的里程碑:

首先,

如上所述,我尝试添加更多列,但没有成功。它导致映射表作为实体存在,但插入显示了同样的问题。 (插入查询,包含有线“SELECT”语句而不是表名)

第二,

我注意到,生成的映射表(在 EM-Designer 中)考虑了 主键的所有列,而我设计的表没有任何(复合)主键在 MySQL-Designer 中(在所有列中只设置了一个唯一键):

第三,

我就像 f*** y** - 并在映射表中添加了一个代理主键列(在数据库设计器中)......

并取消选中 EF-Designer 中任何剩余列的任何 Primary-Key-Membership:

你猜怎么着?它有效:-)

using (MyDb db = new MyDB()){
    Permission_to_Role ptr = new Permission_to_Role();
    ptr.PermissionId = permissionId;
    ptr.RoleId = r.Id;
    ptr.GrantedById = u.Id;
    ptr.GrantedAt = DateTime.Now;

    db.Permission_to_Role.Add(ptr);
    db.SaveChanges();
}

所以,还有三件事要说:

  • 首先(我注意到这一点已经有一段时间了)- 将您的模型与数据库同步时- 有一些更改没有被拾取...而且您将很难弄清楚。它可能只是“索引”,但也可以是“外键约束”甚至“主键设置”之类的东西。 (将 Hibernate (Java) 视为 80/20 规则的大师:Hibernate 完成 80% - 搜索最后的 20% 取决于用户!)
  • 第二:这个问题可能是一个特殊的数据库模式的组合,它依赖于第三方框架并期望一切都自动变得干净整洁......只相信“你自己” !
  • 第三:始终为每个表使用代理主键。它根本没有伤害,但避免了使用本机主键的所有麻烦。 (无论如何,您都可以将其设置为唯一键)

【讨论】:

  • 是的,我们必须在没有任何类型键的表上设置主键。对不起,我在上面告诉过你外键。无论出于何种原因,Entity Framework 都需要一个索引来进行查找。
【解决方案2】:

我真的很想弄清楚这个问题的“原因” - 但现在,我在该关系表中添加了另一列 grantedById(引用 user.id)。

所以,这导致在模型中生成中间实体Permission_To_Role,让我相信它现在可以工作了! (因为这样做了数百次,就像这样:)

 using (MyDb db = new MyDB()){
   Permission_To_Role ptr = new Permission_To_Role();
   ptr.PermissionId = 5;
   ptr.RoleId = 8;
   ptr.GrantedById = Session.CurrentUser.Id;

   db.Permission_To_Role.Add(ptr);
   db.SaveChanges();
}

但是应该可以为Many-To-Many-Mappings 进行数据库插入,只使用 2 个Foreign-Key-Constraint Columns,不是吗?

【讨论】:

  • 我也很想知道和理解这个答案 :) 我认为我们在应用程序中遇到了类似的问题,我们使用 MSSQL。
  • @AussieJoe 我会及时通知您...我现在已经按照说明更新了应用程序 - 但问什么?为“3 Foreign-Key-Columns”获取相同的容易出错的查询......现在尝试使用第四个可为空的“throwAway Column”:-)(我正在更新关于“Everywhere”的关系 - 工作......那里必须是不同的东西导致这个......)
  • @AussieJoe 查看我的第二个回复。我希望这对你也有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多