2013-08-02 62 views
6

我使用实体框架5和MVC 4,.NET 4.5使用Code First迁移。我有两个实体之间的外键以1到0或1的关系。当我尝试为慢跑者创造记录时,一切都会爆炸。我得到的要么是错误消息:分配UserId到外键= null

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

当我运行EF浏览器的导航关系是完美的。目前没有使用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的字段。

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

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

回答

3

多的试验和错误之后,我发现,工作分配的一种方式外键一个值。

首先,我的关系设置不正确:UserProfile类不需要public int? GolferId代表导航属性。 final类看起来如下:

用户配置

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

这样的设置,而无需任何流利的API代码的正确关系。

要分配ForeignKey的值是有点麻烦,我敢肯定有做比这更好的方法。

  1. 而不是定义(ID = 0)的另一方法的脚手架,我使用的的FormCollection。您也可以使用[绑定(包括=“字段1,字段2,字段3”),以确保正确的字段被公布。
  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指引我朝着正确的方向发展。

1

这是你的错误:

public virtual UserProfile UserId { get; set; } 

实体框架代码优先工作与公约,其中之一是基于名称的约定。这意味着,如果你有一个属性“用户ID”,它会寻找一表“用户”,并将其配置为外键,它的表。 我认为这是炸毁,因为你给你的导航属性的传统用于外键属性的名称。

工作的正确方法是:

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

或用流利的语法(你写这在您的语境OnModelCreating方法,或在一个单独的类,从EntityTypeConfiguration继承):

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

编辑:我只注意到你的用户表实际上是所谓的用户配置,这有点使我的回答毫无意义的后半段。尽管如此,我会放弃它,因为它可以是教育。

+1

感谢@Moeri我没有你在上半场利用公共虚拟用户配置用户配置建议的修改),但它仍然给了我(模型是有效的),同样的错误。当添加失败时,JoggerId仍然设置为0。 – Springbokkie

+0

我不知道是否有一些与我的解决方案从根本上有缺陷的,因为即使当我手动在慢跑表中输入数据库值输入用户ID仍杀死模型只是观看手动输入的慢跑者的纪录。 – Springbokkie

2

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

1-在你的慢跑类添加属性:

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); 
} 
+0

谢谢Aguedo。我试图像这样构建它,但在EF查看器中出现错误。我设法找到了一种从UserId分配JoggerId的方法。 – Springbokkie