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

Posted

技术标签:

【中文标题】MVC EF - System.Data.Entity.Infrastructure.DbUpdateException【英文标题】: 【发布时间】:2017-12-10 02:10:31 【问题描述】:

我有两个模型: 用户资料

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; 

用户帖子:

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 H结果=0x80131501 Message=保存不为其关系公开外键属性的实体时发生错误。 EntityEntries 属性将返回 null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地处理保存时的异常。有关详细信息,请参阅 InnerException。

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

内部异常 2:SqlException:无法将值 NULL 插入 列“Id”,表“aspnet-project12017.dbo.UserPosts”;列确实 不允许空值。插入失败。声明已终止。

【问题讨论】:

要么将 UserPost Id 列更改为 intpublic int Id get; set; ,要么将其设置为 [DatabaseGenerated(DatabaseGeneratedOption.None)]。 AFAIK 您不能将字符串/GUID 列设置为自动生成的值列,它仅适用于intlong 或其他数字数据类型(请参阅***.com/questions/8855100/…)。 @TetsuyaYamamoto 因此,如果我想将我的 ID 保留为字符串,那么在创建新帖子时如何生成它,因为它不是自动生成的? 您可以从类构造函数中手动生成它,例如public UserPost() Id = Guid.NewGuid().ToString(); 。当然,您可以在那里设置另一个值而不是 GUID。 我尝试将 Id 更改为 int,但仍然出现相同的错误。 @TetsuyaYamamoto 这是代码优先,对吧?如果您已经在创建包含数据的数据库并且仍然遇到相同的错误,请使用 EF Code First Migration 更改标识列数据类型。只要目标表中Id 的数据类型不变,EF 仍将该列视为string 而不是int 【参考方案1】:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)] 表示标有此类属性的列预期具有从 DBMS 自动生成的值,并且作为一般约定,EF 将 stringuniqueidentifier (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; 

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

    有时 EF 会默认您尝试插入标识列。如果发生这种情况,请将StoreGeneratedPattern.NoneDatabaseGenerationOption.None 临时设置为UserPost.Id

    protected void OnModelCreating(DbModelBuilder modelBuilder)
    
        // other entities
    
        modelBuilder.Entity<UserPost>()
           .HasKey(p => p.Id)
           .Property(p => p.Id)
           .StoreGeneratedPattern = StoreGeneratedPattern.None;
    
       // other entities
    
    

    确保模型已修改为包含实际的Id 属性(需要时尝试删除数据库中的UserPost 表)。

    通过包管理器控制台运行迁移,如下所示:

    Add-Migration "Set Id as Identity Specification"
    

    在从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);                
    
    

如果您仍希望字符串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

【讨论】:

以上是关于MVC EF - System.Data.Entity.Infrastructure.DbUpdateException的主要内容,如果未能解决你的问题,请参考以下文章

在 MVC 视图中显示存储过程的结果 (EF 5 / MVC 4)

[实战]MVC5+EF6+MySql企业网盘实战(28)——其他列表

MVC5 + EF6 简单示例

如何用mvc+ef 做一个登录界面

MiniProfiler(MiniProfiler.EF6监控调试MVC5和EF6的性能)

EF中的模型和MVC中的模型