MVC EF - System.Data.Entity.Infrastructure.DbUpdateException

时间:2017-07-06 07:40:46

标签: c# mysql sql-server asp.net-mvc entity-framework

我有两个型号: 用户配置

public class UserProfile
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ApplicationUser ApplicationUser { get; set; }
    public virtual ICollection<UserPost> UserPost { get; set; }
}

UserPost:

public class UserPost
{  
   [Key]
   [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public string Id { get; set; }
   public string PostTitle { get; set; }
   public virtual UserProfile UserProfile { get; set; }
   public string Contents { get; set; }
}

UserProfile与AspNetUser具有一对一的关系。

UserProfile与UserPost有一对多的关系。

当我在我的控制器的Create方法中将UserPost添加到数据库时,我得到一个System.Data.Entity.Infrastructure.DbUpdateException

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize]
    public ActionResult Create([Bind(Include = "PostTitle, Content")] UserPost post)
    {
        if (ModelState.IsValid)
        {

            UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
            var user = UserManager.FindById(User.Identity.GetUserId());
            post.UserProfile = user.UserProfile;
            db.UserPosts.Add(post);
            db.SaveChanges();//error here
            return RedirectToAction("Index");
        }

        return View(post);
    }
  

发生了System.Data.Entity.Infrastructure.DbUpdateException     的HResult = 0x80131501     Message =保存未公开其关系的外键属性的实体时发生错误。 EntityEntries属性将返回null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅InnerException。

     

内部异常1:UpdateException:更新时发生错误   条目。有关详细信息,请参阅内部异常。

     

内部异常2:SqlException:无法将值NULL插入   栏&#39; Id&#39;,table&#39; aspnet-project12017.dbo.UserPosts&#39 ;;专栏   不允许空值。 INSERT失败。声明已经终止。

1 个答案:

答案 0 :(得分:0)

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]表示标有此类属性的列预计会从DBMS中自动生成值,并且作为EF处理string&amp;的一般约定。 uniqueidentifier(GUID)列为非自动递增,因此必须以另一种方式(即通过构造函数赋值)分配这些列值。

解决主键自动递增标识列的空问题的常用方法只需将其设置为数值数据类型(例如int):

public class UserPost
{  
   [Key]
   [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public int Id { get; set; } // change to numeric data type
   public string PostTitle { get; set; }
   public virtual UserProfile UserProfile { get; set; }
   public string Contents { get; set; }
}

然后,在执行迁移时,请执行以下步骤:

  1. 有时EF默认情况下会尝试插入标识列。如果发生这种情况,请设置StoreGeneratedPattern.None&amp;暂时DatabaseGenerationOption.NoneUserPost.Id

    protected void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // other entities
    
        modelBuilder.Entity<UserPost>()
           .HasKey(p => p.Id)
           .Property(p => p.Id)
           .StoreGeneratedPattern = StoreGeneratedPattern.None;
    
       // other entities
    }
    
  2. 确保已修改模型以包含实际的Id属性(在需要时尝试删除数据库中的UserPost表。)

  3. 通过Package Manager控制台运行迁移,如下所示:

    Add-Migration "Set Id as Identity Specification"
    
  4. DbMigration生成的课程中,您会看到两种方法:Up()Down()。修改Up()部分以在那里设置int数据类型(并在需要时重新运行迁移过程):

    public override void Up()
    {
        CreateTable(
              "dbo.UserPost",
              c => new
              {
                  Id = c.Int(nullable: false, identity: true),
                  PostTitle = c.String(),
                  Contents = c.String(),
              })
              .PrimaryKey(t => t.Id);                
    }
    
  5. 如果您仍希望将字符串Id列作为UserPost的主键,则需要将其设置为[DatabaseGenerated(DatabaseGeneratedOption.None)]并从类构造函数手动分配值(请注意,生成的值必须是唯一的根本不会或EF会告诉你“不能在对象中插入重复的密钥”):

    public class UserPost
    {
        public UserPost()
        {
            Id = [[autogenerated value here]];
        }
    
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public string Id { get; set; }
    
        // other properties
    }
    

    相关问题:

    MVC5 EF6 Seed Method: Cannot insert NULL into column 'Id' table AspNetUsers

    Cannot insert the value NULL into column 'Id' (Database first)

    Code first - Cannot insert the value NULL into column 'Id'

    Entity Framework Cannot insert the value NULL into column Identity Specification set to No