简体   繁体   English

实体框架未将父ID映射为子表中的外键

[英]Entity Framework not mapping parent id as foreign key in child table

I am using Entity Framework 5.0, I want to insert rows in table which are in a parent-child relationship ie user and user_role . 我正在使用Entity Framework 5.0,我想在表中插入具有父子关系的行,即useruser_role

  • user contains columns user_id, first_names, last_name user包含列user_id, first_names, last_name

  • user_role contains columns role_id, role_name, user_id user_role包含role_id, role_name, user_id

I've setup Entity Framework and also can see their association in designer viewer, now when I try to execute my code, constraint exception occurs which says that user_id is not mapped in user_role table 我已经设置了实体框架,并且还可以在设计器查看器中看到它们的关联,现在当我尝试执行代码时,发生约束异常,该异常表示user_id未映射到user_role表中

Microsoft Entity Framework - not working: Microsoft实体框架-不起作用:

using (MicrosoftEntities context = new MicrosoftEntities())
{
     USER user = new USER();
     user.FIRST_NAMES = "u";
     user.LAST_NAME = "u";

     user.USER_ROLE.Add(new USER_ROLE() { ROLE_ID = 10001, role_name ="a" });
     user.USER_ROLE.Add(new USER_ROLE() { ROLE_ID = 10002, role_name ="b" });

     context.USERZs.Add(user);
     context.SaveChanges();
}

Telerik Entity Framework - working perfectly fine: Telerik实体框架-正常工作:

using (TelerikEntities context = new TelerikEntities())
{
    Telerik_USER user1 = new Telerik_USER();
    user1.FIRST_NAMES = "u";
    user1.LAST_NAME = "u";

    user1.Telerik_USER_ROLE.Add(new Telerik_USER_ROLE() { ROLE_ID = 10001 });
    user1.Telerik_USER_ROLE.Add(new Telerik_USER_ROLE() { ROLE_ID = 10002 });

    context.Add(user1);
    context.SaveChanges();
}

What am I doing wrong? 我究竟做错了什么? Please help me out. 请帮帮我。

I am compelled to use Microsoft Entity Framework. 我被迫使用Microsoft Entity Framework。

Entity Framework classes 实体框架类

public partial class USER
{
    public USER()
    {
        this.USER_ROLE = new HashSet<USER_ROLE>();
    }

    public long USER_ID { get; set; }
    public string FIRST_NAMES { get; set; }
    public string LAST_NAME { get; set; }

    public virtual ICollection<USER_ROLE> USER_ROLE { get; set; }
  }

public partial class USER_ROLE
{
    public long USER_ROLE_ID { get; set; }
    public Nullable<long> USER_ID { get; set; }
    public Nullable<long> ROLE_ID { get; set; }
    public Nullable<string> ROLE_NAME { get; set; }
    public virtual USER USER { get; set; }
}

The user must exist before you add the role. 在添加角色之前,用户必须存在。 You can't do it at the same time. 您不能同时进行。 You should do it in a transaction, but I will post working code for the inserts not the trans. 您应该在事务中执行此操作,但是我将发布插入内容的工作代码,而不是trans。

using (MicrosoftEntities context = new MicrosoftEntities())
{
     USER user = new USER();
     user.FIRST_NAMES = "u";
     user.LAST_NAME = "u";

     context.USERZs.Add(user);
     context.SaveChanges();


     user.USER_ROLE.Add(new USER_ROLE() { ROLE_ID = 10001, role_name ="a", USER_ID = user.USER_ID });
     user.USER_ROLE.Add(new USER_ROLE() { ROLE_ID = 10002, role_name ="b", USER_ID = user.USER_ID });
     context.SaveChanges();

}

The problem is that your new child entities are not being tracked by EF at the time of insertion (because you newed them). 问题是,你的新子实体不被跟踪EF在插入时(因为你newed它们)。 If you used proxies and would let EF generate its own ids, it should work. 如果您使用代理并让EF生成自己的ID,它应该可以工作。

The common way of doing this is attaching the entities before SaveChanges() , in your case: 常见的做法是在您的情况下,在SaveChanges()之前附加实体:

using (MicrosoftEntities context = new MicrosoftEntities())
{
     USER user = new USER();
     user.FIRST_NAMES = "u";
     user.LAST_NAME = "u";

     /** Notice we don't specify a ROLE_ID here, we let EF generate it **/
     user.USER_ROLE.Add(new USER_ROLE() { role_name ="a" });
     user.USER_ROLE.Add(new USER_ROLE() { role_name ="b" });

     /** attach all entities to the context **/
     foreach(var role in user.USER_ROLE)
     {
       context.Entry(role).State = role.ROLE_ID == default(long) ? EntityState.Added : EntityState.Modified;
     }

     context.USERZs.Add(user);
     context.SaveChanges();
}

In EF7 you could use AttachGraph (or TrackGraph , not sure how it's called in final versions), in EF6 you need to do it by hand. 在EF7中,您可以使用AttachGraph (或TrackGraph ,不确定最终版本中的调用方式),而在TrackGraph ,您需要手工完成。

This could be further simplified by using proxies, creating the entities with DbContext.Create instead of new 'ing them, and having a navigation property on USER_ROLE which is the USER (in case it's 0:n, which we don't know) and setting the User property on the role: this would take care of attaching and setting the correct ids on saving. 这可以通过使用代理,使用DbContext.Create创建实体(而不是new实体)并在USER_ROLE上具有USER (如果是0:n,我们不知道)的导航属性来进一步简化,并且在角色上设置User属性:这将在保存时附加并设置正确的ID。

Sounds to me that you are moving your database issues to an ORM, and you should be abstracting from those issues. 在我看来,您正在将数据库问题转移到ORM,并且应该从这些问题中抽象出来。 Generating your own ID's make no sense in an ORM: if things were great (which aren't, in practice), having an ORM should theoretically allow you to not care about id's at all, and use objects for relationships, not ids. 在ORM中生成自己的ID是没有意义的:如果事情很好(实际上不是),那么从理论上讲,拥有ORM应该完全不关心ID,而是将对象用于关系而非ID。

If you plan to make the work of the ORM in your code, forget about EF and ORMs and get some SQL mapper (like Dapper.NET or similar), which does wonders and it's way more performant than EF. 如果您打算在代码中使用ORM,请忽略EF和ORM,并获得一些SQL映射器(例如Dapper.NET或类似的东西),这确实令人惊奇,并且比EF具有更高的性能。

You need to save the new User first so you get a database generated Id (assuming it is auto generated of course): 您需要先保存新User以便获得数据库生成的ID(当然,当然是假定它是自动生成的):

using (MicrosoftEntities context = new MicrosoftEntities())
using(var transaction = context.DataBase.BeginTransaction())
{
 USER user = new USER();
 user.FIRST_NAMES = "u";
 user.LAST_NAME = "u";
 context.Users.Add(user);
 context.SaveChanges();

 user.USER_ROLE.Add(new USER_ROLE() { ROLE_ID = 10001, role_name ="a", userId = user.Id});
 user.USER_ROLE.Add(new USER_ROLE() { ROLE_ID = 10002, role_name ="b", userId = user.Id});

 context.SaveChanges();
 transaction.Commit();
}

Only works with EF6+ 仅适用于EF6 +

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

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