简体   繁体   English

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

[英]Entity-Framework: Create Many-To-Many-Relations

We are using the "DB-First" approach for an application, cause the Database is shared between various applications, so it should be the "master". 我们对应用程序使用“ DB-First”方法,因为数据库在各种应用程序之间共享,所以它应该是“主数据库”。 (MySQL) (MySQL的)

We have 3 simple tables, responsible for the Role-To-Permission Assignment, like this: 我们有3个简单的表,负责角色到权限的分配,如下所示:

在此处输入图片说明

The Visual-Studio Model Designer (after building the model from the database) perfectly fine recocnices this as a "Many-To-Many" relation, not even generating a "Role_to_permission"-Entity, as there are no further attributes on the assignment) Visual-Studio模型设计器(从数据库中构建模型之后)可以很好地将其识别为“多对多”关系,甚至不会生成“ Role_to_permission” -Entity,因为分配没有其他属性)

在此处输入图片说明

Until now, we created those entries in the database, which lead to the expected outcome within the application. 到目前为止,我们已经在数据库中创建了这些条目,这些条目导致了应用程序内的预期结果。 (Accessing mappings) (访问映射)

Currently we are working on an Interface, allowing to assign "Permissions" to "Roles". 当前,我们正在开发接口,允许将“权限”分配给“角色”。 And here, I'm a little stuck: 在这里,我有点卡住了:

  • If such a relation has another attribute (such as required or a date ), the EMF creates an own entity for the relation - let's assume Permission_To_Role . 如果这样的关系具有另一个属性(例如requireddate ),则EMF会为该关系创建一个自己的实体-让我们假设Permission_To_Role

then, I can "easily" create a relation, with the following code: 然后,我可以使用以下代码“轻松”创建关系:

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();
}

Whatsoever - in this case - we don't have any additional attribute on the mapping, so the additional class is avoided by the EF Framework. 无论如何-在这种情况下-映射上没有任何其他属性,因此EF Framework 避免了其他类。

Im now trying hard to create a relation, but without success: 我现在正在努力建立关系,但没有成功:

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();
}

This always results in an Exception, and I can't figure out why (IDs are existing and correct) ... 这总是导致异常,我不知道为什么(ID存在并且正确)...

Exception of db.SaveChanges() : db.SaveChanges()异常:

An exception of type 'System.Data.Entity.Infrastructure.DbUpdateException' occurred in EntityFramework.dll but was not handled in user code EntityFramework.dll中发生类型为'System.Data.Entity.Infrastructure.DbUpdateException'的异常,但未在用户代码中处理

Additional information: An error occurred while saving entities that do not expose foreign key properties for their relationships. 附加信息:保存不公开外键属性为其关系的实体时发生错误。 The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. EntityEntries属性将返回null,因为无法将单个实体标识为异常的来源。 Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. 通过在实体类型中公开外键属性,可以简化保存时的异常处理。 See the InnerException for details. 有关详细信息,请参见InnerException。

Inner Exception: 内部异常:

An error occurred while updating the entries. 更新条目时发生错误。 See the inner exception for details. 有关详细信息,请参见内部异常。

Inner Inner Exception: 内部内部异常:

You have an error in your SQL syntax; 您的SQL语法有误; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT Permission_to_Role . PermissionId , Permission_to_Role . RoleId FROM' at line 1 检查对应于你的MySQL服务器版本使用附近的正确语法手册“(SELECT Permission_to_RolePermissionIdPermission_to_RoleRoleId FROM”在1号线

Ideas? 想法?


Update: 更新:

SHOW CREATE TABLE Permission_to_Role;

output: 输出:

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

Update2: UPDATE2:

As of the current comments: I enabled the output for queries generated by the EF, and found this charm - which is obviously a malformated Query: 截至当前评论:我为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)

The query actual should be: 实际查询应为:

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

So, I think this looks like a "bug"? 所以,我认为这看起来像个“虫子”? As mentioned above: 正如刚才提到的:

Whatsoever - in this case - we don't have any additional attribute on the mapping, so the additional class is avoided by the EF Framework. 无论如何-在这种情况下-映射上没有任何其他属性,因此EF Framework 避免了其他类。

there is no intermediate Permission_To_Role Entity, hence it seems like EF is trying to replace this table name with the query 没有中间的Permission_To_Role实体,因此似乎EF尝试用查询替换该表名

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

EVEN upon inserts... (Maybe this works for MsSQL and is a bad implementation for the MySQL Connector?) 甚至在插入时...(也许这适用于MsSQL,并且对于MySQL Connector是错误的实现?)

I'd really like to figure out the "cause" of this issue - but for now, I added another column grantedById (referencing user.id ) to that relation table. 我真的很想弄清楚这个问题的“原因”,但现在,我在该关系表中添加了另一列grantedById (引用user.id )。

在此处输入图片说明

So, this caused the intermediate entity Permission_To_Role to be generated in the Model, and made me believe it's going to work now! 因此,这导致在模型中生成中间实体Permission_To_Role ,并让我相信它现在可以正常工作! (Cause done that hundreds of times, like this: ) (原因是执行了数百次,如下所示:)

 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();
}

But It should be possible to do Database-Inserts for Many-To-Many-Mappings with 2 Foreign-Key-Constraint Columns ONLY as well, shouldn't it? 但是,也应该只对带有2个Foreign-Key-Constraint Columns Many-To-Many-Mappings进行数据库插入,不是吗?

I'm a little tired right now, but finally got it to work. 我现在有点累,但是终于开始工作了。

I'm not 100% sure to outline the real problem, cause I changed a lot of things - but the following "findings" are kind of milestones while resolving this problem: 我不是100%肯定会概述真正的问题,因为我做了很多更改-但是以下“发现”是解决此问题时的里程碑:

First, 第一,

I tried to add more columns as mentioned above, which did nor work out. 如上所述,我尝试添加更多列,但没有成功。 It caused the Mapping-Table to be present as entity, but the insert showed the same problem. 这导致Mapping-Table作为实体出现,但是插入内容显示了相同的问题。 (Insert Query, containing wired "SELECT" Statement instead of table name) (插入查询,包含有线的“ SELECT”语句而不是表名)

Second, 第二,

I noted, that the generated Mapping-Table (In EM-Designer) took ALL columns into account for the primary key , while I designed the table without any (composite) Primary Key in the MySQL-Designer (only a unique key was setup accross all columns): 我注意到,生成的映射表(在EM-Designer中)考虑了所有列作为主键而我在MySQL-Designer中设计了没有任何(复合)主键的表 (只有一个唯一的键被安装了)所有列):

在此处输入图片说明

Third, 第三,

I was like f*** y** - and added a surrogate Primary Key-Column to the mapping-table (In the database designer)... 我就像f *** y **-并在映射表中添加了代理主键列(在数据库设计器中)...

在此处输入图片说明

and unchecked any Primary-Key-Membership in the EF-Designer for any remaining column: 并取消选中EF-Designer中任何剩余列的主键成员资格:

在此处输入图片说明

And guess what? 你猜怎么着? It works :-) 有用 :-)

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();
}

So, there are three things left to say: 因此,还有三件事要说:

  • First (I noted this quite some time) - When synchronsizing your Model with the database - there are changes that aren't picked up... And you'll have a hard time figuring it out. 首先(我在相当长的时间内记下了时间)-在将模型与数据库同步时-有一些未选择的更改...而且您将很难找出它。 It might only be "Indexes", but it also can be stuff like "Foreign Key Constraints" or even "Primary-Key-Settings". 它可能只是“索引”,但也可能是诸如“外键约束”甚至“主键设置”之类的东西。 (Consider Hibernate (Java) as the master of the 80/20 rule: Hibernate does 80% - Searching the final 20% is up to the user!) (将Hibernate (Java)视为80/20规则的主要部分:Hibernate占80%-搜索最终的20%取决于用户!)
  • Second: This problem might be a combination of a special database-schema, relying on third-party-frameworks and expecting about everything to be nice and clean automatically... Only trust "yourself"! 第二:这个问题可能是特殊的数据库模式的组合,它依赖于第三方框架,并期望所有东西都自动变得干净整洁……只相信“自己”!
  • Third: Always use a surrogate Primary Key for every table. 第三:始终为每个表使用代理主键。 It doesn't hurt at all, but avoids all the hassle with native-primary keys. 它完全没有伤害,但是避免了使用本机主键的所有麻烦。 (Which you can setup as unique keys anyway) (仍然可以将其设置为唯一键)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM