将UserId分配给外键= null

时间:2013-08-02 08:50:36

标签: c# asp.net-mvc entity-framework asp.net-mvc-4

我正在使用Entity Framework 5和MVC 4,.NET 4.5使用Code First迁移。我在两个实体之间有1到0或1关系的外键。当我尝试为Jogger创建记录时,一切都会爆炸。我得到的错误消息是:

  • 外键是空引用
  • dbo.Jogger不存在
  • 未处理的异常......没有元数据。

当我运行EF Viewer时,导航关系是完美的。目前没有使用Fluent API代码。

用户类

     [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }

    // Other properties

    public int? JoggerId { get; set; }
    public virtual Jogger Jogger { get; set; }

Jogger Class

    [ForeignKey("UserId")]
    public int JoggerId { get; set; }

    public virtual UserProfile UserId { get; set; }

生成JoggerController时,它会为Get和Post Methods生成此代码:

// GET: /Jogger/Create

    public ActionResult Create()
    {
        ViewBag.JoggerId = new SelectList(db.UserProfiles, "UserId", "UserName");
        return View();
    }

    //
    // POST: /Jogger/Create

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Jogger jogger)
    {



        if (ModelState.IsValid)
        {
            db.Jogger.Add(jogger);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        ViewBag.JoggerId = new SelectList(db.UserProfiles, "UserId", "UserName", jogger.JoggerId);
        return View(jogger);
    }

在Jogger / Create视图中,根据生成的代码,没有JoggerId或UserId的字段。

通常,它在代码的(ModelState.IsValid)部分失败,其中Output显示JoggerId = 0和UserId = null。

我还没有在asp.net网站上的Contoso大学教程中看到这种行为,我也查看过MSDN Learn EF网站。我似乎无法解决这个问题。您的建议表示赞赏。

3 个答案:

答案 0 :(得分:3)

经过多次试验和错误后,我找到了一种方法,可以为外键分配一个值。

首先,我的关系设置不正确: UserProfile Class 不需要public int? GolferId代表导航属性。最后的课程如下:

UserProfile

  [Key]
  [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
  public int UserId { get; set; }
  public string UserName { get; set; }

  // Navigation properties
  public virtual Jogger Jogger { get; set; }

Jogger Class

[Key] 
[ForeignKey("UserId")]
public int JoggerId { get; set; }

public string Pronation {get; set;}

public virtual UserProfile UserId { get; set; }

这可以设置正确的关系,而无需任何Fluent API代码。

分配ForeignKey值有点棘手,我确信有比这更好的方法。

  1. 我使用了FormCollection而不是其他定义的脚手架方法(id = 0)。您还可以使用[Bind(Include =“field1,field2,field3”)]来确保发布正确的字段。
  2. 使用User.Identity.Name
  3. 登录用户的UserId还有很长的路要走。
  4. FormCollection允许我引用并保存其他字段,例如旋前

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(FormCollection values)
    {
    
        var jogger = new Jogger();
        TryUpdateModel(jogger);
    
        var context = new TestContext();
        var userqq = User.Identity.Name;
        var user = context.UserProfiles.SingleOrDefault(u => u.UserName == userqq);
    
        if (ModelState.IsValid)
        {
    
                jogger.JoggerId = user.UserId;
                jogger.Pronation = values["Pronation"];
    
    
                db.Joggers.Add(jogger);
                db.SaveChanges();
               return View();
    
    
        }
            ViewBag.JoggerId = new SelectList(db.UserProfiles, "UserId", "UserName", jogger.JoggerId);
            return View(jogger);
    
    }
    
  5. 这根本不是很好,但确实有效。感谢@Moeri指出我正确的方向。

答案 1 :(得分:2)

错误发生在数据库模型中。 实体框架代码优先始终需要配置一对一关系。在这些情况下,Code First无法确定哪个类是依赖的。

1-在您的Jogger类中添加属性:

public virtual User User { get; set; }

2 - 在OnModelCreating方法中添加:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
      // One to One relationship
      modelBuilder.Entity<User>()
                        .HasOptional(t => t.Jogger)
                        .WithOptionalDependent(m => m.User);
}

答案 2 :(得分:1)

这是您的错误:

public virtual UserProfile UserId { get; set; }

实体框架代码首先使用约定,其中一个是基于名称的约定。这意味着如果您有一个属性“UserId”,它将查找表“User”并将其配置为该表的外键。 我认为它正在爆炸,因为你给了你的导航属性一个通常用于外键属性的名称。

正确的工作方式是:

public virtual int? UserId { get; set; }
public virtual User User { get; set; }

如果您希望将您的属性称为“UserProfileId”,则必须使用“ForeignKey”属性或fluent配置语法让Entity Framework知道这是一个外键:

public virtual int? UserProfileId{ get; set; }

[ForeignKey("UserProfileId")
public virtual User User { get; set; }

或使用流畅的语法(在Context的OnModelCreating方法中,或在从EntityTypeConfiguration继承的单独类中写入):

HasRequired(j => j.User).WithMany().HasForeignKey(i => i.UserProfileId)

编辑:我刚刚注意到你的User表实际上被称为UserProfile,这种方式使我的响应的后半部分无法实现。尽管如此,我会保留它,因为它可以是教育性的。