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

时间:2016-01-04 17:05:05

标签: c# entity-framework

我正在使用Entity Framework 5.0,我想在表中插入一些父子关系中的行,即useruser_role

  • user包含user_id, first_names, last_name

  • user_role包含role_id, role_name, user_id

我已经设置了Entity Framework并且也可以在设计器查看器中看到它们的关联,现在当我尝试执行我的代码时,会发生约束异常,其中user_id未映射到user_role表< / p>

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 - 完美运行:

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

我做错了什么?请帮帮我。

我被迫使用Microsoft Entity Framework。

实体框架类

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

3 个答案:

答案 0 :(得分:1)

在添加角色之前,用户必须存在。你不能同时做到这一点。您应该在事务中执行此操作,但我将发布插入的工作代码而不是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();

}

答案 1 :(得分:0)

您需要先保存新的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();
}

仅适用于EF6 +

答案 2 :(得分:0)

问题是EF在插入时没有跟踪您的新子实体(因为您newed他们)。如果您使用代理并让EF生成自己的ID,它应该可以工作。

执行此操作的常用方法是在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();
}

在EF7中,您可以使用AttachGraph(或TrackGraph,不确定在最终版本中如何调用它),在EF6中您需要手动执行此操作。

这可以通过使用代理进一步简化,使用DbContext.Create而不是new创建实体,并在USER_ROLE上创建USER的导航属性(如果它是0:n,我们不知道)并在角色上设置User属性:这将负责在保存时附加和设置正确的ID。

听起来您将数据库问题转移到ORM,您应该从这些问题中抽象出来。在ORM中生成自己的ID是没有意义的:如果事情很好(实际上并非如此),理论上,拥有ORM应该让你根本不关心id,并使用对象来建立关系,而不是id。 / p>

如果您计划在代码中完成ORM的工作,请忘记EF和ORM并获取一些SQL映射器(如Dapper.NET或类似的),这会产生奇迹,并且它比EF更具性能。< / p>