实体框架:创建多对多关系

zqdjd7g9  于 2021-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(324)

我们对应用程序使用“db-first”方法,因为数据库在不同的应用程序之间共享,所以它应该是“master”(mysql数据库)
我们有3个简单的表,负责角色到权限的分配,如下所示:

visualstudio模型设计器(在从数据库构建模型之后)完美地将其识别为“多对多”关系,甚至不生成“角色到权限”实体,因为在赋值上没有其他属性)

到目前为止,我们在数据库中创建了这些条目,从而在应用程序中获得了预期的结果(访问Map)
目前我们正在开发一个接口,允许将“权限”分配给“角色”。在这里,我有点卡住了:
如果这样的关系有另一个属性(例如 required 或者 date ),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();
}

无论如何,在这种情况下,我们在Map上没有任何附加属性,因此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() :
entityframework.dll中发生类型为“system.data.entity.infrastructure.dbupdateexception”的异常,但未在用户代码中处理
其他信息:保存不公开其关系的外键属性的实体时出错。entityentries属性将返回null,因为无法将单个实体标识为异常源。保存时处理异常可以通过在实体类型中公开外键属性来简化。有关详细信息,请参见innerexception。
内部异常:
更新条目时出错。有关详细信息,请参见内部异常。
内部异常:
sql语法有错误;请查看与mysql服务器版本对应的手册,以了解要使用的正确语法 Permission_to_Role . PermissionId , Permission_to_Role . RoleId 从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:

截至目前的评论:我为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)

所以,我觉得这看起来像“虫子”?如上所述:
无论如何,在这种情况下,我们在Map上没有任何附加属性,因此ef框架避免了附加类。
没有中间产物 Permission_To_Role 实体,因此似乎ef正在尝试用查询替换这个表名

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

即使是插页(也许这适用于mssql,对mysql连接器来说是个糟糕的实现?)

tjjdgumg

tjjdgumg1#

我现在有点累,但总算有点用了。
我不能百分之百肯定地勾勒出真正的问题,因为我改变了很多事情——但以下“发现”是解决这个问题的里程碑:

首先,

我试着像上面提到的那样添加更多的列,但没有成功。它导致Map表以实体的形式出现,但是insert显示了相同的问题(插入查询,包含有线“select”语句而不是表名)

其次,

我注意到,生成的Map表(在em designer中)考虑了主键的所有列,而我在mysql designer中设计的表没有任何(复合)主键(只有一个唯一的键是setup accross all columns):

第三,

我就像f*y—在Map表中添加了一个代理主键列(在数据库设计器中)。。。

并取消选中ef设计器中任何剩余列的任何主键成员身份:

你猜怎么着?有效:-)

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%取决于用户!)
第二:这个问题可能是一个特殊的数据库模式的组合,依赖于第三方框架,并期望所有的东西都是好的和干净的自动。。。只相信“你自己”!
第三:始终为每个表使用代理主键。它一点也不疼,但是避免了使用本机主键的所有麻烦(您可以将其设置为唯一键)

0ve6wy6x

0ve6wy6x2#

我真的很想找出这个问题的“原因”-但现在,我添加了另一个专栏 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 也一样,不是吗?

相关问题