将UserId分配给外键=null

本文关键字:null UserId 分配 | 更新日期: 2023-09-27 18:25:59

我使用实体框架5和MVC 4,.NET 4.5使用代码优先迁移。我在1到0或1关系中的两个实体之间有外键。当我试图为乔格创造纪录时,一切都崩溃了。我收到的错误消息要么是:

  • 外键是空引用
  • 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; }

慢跑类

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

当JoggerController生成时,它会为Get和Post方法生成以下代码:

// 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网站。我似乎解决不了这个问题。非常感谢你的建议。

将UserId分配给外键=null

经过多次尝试和错误,我找到了一种为外键赋值的方法。

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

用户配置文件

  [Key]
  [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
  public int UserId { get; set; }
  public string UserName { get; set; }
  // Navigation properties
  public virtual Jogger Jogger { get; set; }

慢跑类

[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. 获取登录用户的UserId需要很长的路要走,这将利用User.Identity.Name
  3. 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);
    }
    

这一点都不好看,但确实有效。感谢@Moeri为我指明了正确的方向。

错误在数据库模型中。实体框架代码优先总是需要对一对一关系进行配置。在这些情况下,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);
}

这是您的错误:

public virtual UserProfile UserId { get; set; }

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

正确的工作方式是:

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

如果你希望你的属性被称为"UserProfileId",你必须使用"ForeignKey"属性或流畅的配置语法来让实体框架知道这是一个外键:

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,这在某种程度上使我的响应的后半部分变得毫无意义。尽管如此,我还是会让它保持原样,因为它可能具有教育意义。