• Entity Framework——常见报错总结


    1 实体属性配置为IsRequired()对更新的影响

    抛出异常类型DbEntityValidationException

    表结构:

    实体:

    public class User
        {
            public int Id { get; set; }
            /// <summary>
            /// 账号
            /// </summary>
            public string Account { get; set; }
            /// <summary>
            /// 邮箱
            /// </summary>
            public string Email { get; set; }
            /// <summary>
            /// 昵称
            /// </summary>
            public string Nickname { get; set; }
            /// <summary>
            /// 头像
            /// </summary>
            public string AvatarId { get; set; }
            /// <summary>
            /// 记录插入时间
            /// </summary>
            public DateTime InsertTime { get; set; }
            /// <summary>
            /// 记录修改时间
            /// </summary>
            public DateTime UpdateTime { get; set; }
        }

    实体配置:

           modelBuilder.Entity<User>().Property(u => u.Account)
                    .IsRequired()
                    .IsUnicode(false)
                    .HasMaxLength(50);
                modelBuilder.Entity<User>().Property(u => u.Email)
                    .IsRequired()
                    .IsUnicode(false)
                    .HasMaxLength(100);
                modelBuilder.Entity<User>().Property(u => u.Nickname)
                    .IsUnicode(false)
                    .HasMaxLength(50);
                modelBuilder.Entity<User>().Property(u => u.AvatarId)
                    .IsOptional()
                    .HasMaxLength(100);

    CustomDbContext继承自DbContext

    [DbConfigurationType(typeof(MySqlEFConfiguration))]
        public class CustomDbContext : DbContext
        {
            public CustomDbContext()
                : base("name=Master")
            {
                
                this.Configuration.LazyLoadingEnabled = false; 
                //DropCreateDatabaseIfModelChanges
                //new DropCreateDatabaseAlways<CustomDbContext>()
                Database.SetInitializer<CustomDbContext>(null);
            }
    
            public DbSet<User> Users { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                EntityConfiguration.Set(modelBuilder);
            }
    }

    更新操作:

    using (CustomDbContext db = new CustomDbContext())
    {
                        User user = new User 
                        {
                            Id = 1,
                            Email = "test@1622.com",
                        };
                        DbEntityEntry<User> entry = db.Entry<User>(user);
                        entry.State = EntityState.Unchanged;
                        entry.Property(t => t.Email).IsModified = true;
    
                        int num = db.SaveChanges();
    }

    执行操作,报错信息如下:

    查看EntityValidationErrors

    只能看到{System.Data.Entity.Validation.DbEntityValidationResult},没有更详细的信息。

    如果将上述代码用try..catch包起来,如下写法:

    try
    {
    //执行代码
    }
    catch (DbEntityValidationException ex)
    {
        var e = ex.EntityValidationErrors;
    }
    catch (Exception ex)
    {
    }

    一层一层地打开,看到真正导致异常的原因,看到下面的截图:

    分析实体配置发现,Account属性被设置为IsRequired,那么在更新实体的时候,即使不更新这个字段,也要给这个字段赋值,那么赋值后观察:

    更新操作代码变为

                    using (CustomDbContext db = new CustomDbContext())
                    {
                        User user = new User 
                        {
                            Id = 1,
                            Email = "test@1622.com",
                            Account = "a"
                        };
                        DbEntityEntry<User> entry = db.Entry<User>(user);
                        entry.State = EntityState.Unchanged;
                        entry.Property(t => t.Email).IsModified = true;
    
                        int num = db.SaveChanges();
                    }        

    经过上述调整后,更新成功。

    那么换一个思路,将Account属性被设置为IsOptional()是不是也可以呢?

    修改实体配置,将Account属性设置按如下修改,并注掉上面的Account = "a"

    modelBuilder.Entity<User>().Property(u => u.Account)

                    .IsOptional()

                    .IsUnicode(false)

                    .HasMaxLength(50);

    执行测试,更改成功。

    得出结论:在实体配置时,指定了为必选的字段,那么更新操作时,构造实例一定要对必选(IsRequired())字段赋值。

    上述测试中还有一个值得考虑的细节,构造User实例的时候,只对Id,Email进行了赋值,而没有对其他属性进行赋值,那么为什么会成功呢?那么必定是未进行任何设置的实体属性默认是IsOptional()。这跟表结构中的字段类型设置为Not Null有无关联呢,从测试结果看就本类应用无必然联系。

    总结:

    a.实体配置中指定了实体属性为IsRequired(),更新操作构造类的实例时必对此属性赋值。

    b.不进行配置的实体属性默认为IsOptional()

    c.表结构中字段是否为Not Null对上述规则无影响。

    2 更新报错:

    An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.

    异常类型:System.Data.Entity.Infrastructure.DbUpdateConcurrencyException

    实体属性配置如上例所示。

    操作代码:

                    using (CustomDbContext db = new CustomDbContext())
                    {
                        User user = new User 
                        {
                            Id = 1,
                            Email = "test@132.com",
                        };
                        DbEntityEntry<User> entry = db.Entry<User>(user);
                        entry.State = EntityState.Unchanged;
                        entry.Property(t => t.Email).IsModified = true;
    
                        User user1 = new User
                        {
                            Id = 1,
                            Email = "test@132.com",
                        };
                        DbEntityEntry<User> entry1 = db.Entry<User>(user1);
                        entry1.State = EntityState.Unchanged;
                        entry1.Property(t => t.Email).IsModified = true;
    
                        int num = db.SaveChanges();
                    }    

    执行操作

    涉及到两次修改操作,两次操作构造了两个实例,但是实例的属性Id有相同的值。

    如果两次操作的是同一个实例,而不是不同的实例,那么不会抛出异常,代码如下:

                    using (CustomDbContext db = new CustomDbContext())
                    {
                        User user = new User 
                        {
                            Id = 1,
                            Email = "test@132.com",
                        };
                        DbEntityEntry<User> entry = db.Entry<User>(user);
                        entry.State = EntityState.Unchanged;
                        entry.Property(t => t.Email).IsModified = true;
    
                        DbEntityEntry<User> entry1 = db.Entry<User>(user);
                        entry1.State = EntityState.Unchanged;
                        entry1.Property(t => t.Email).IsModified = true;
    
                        int num = db.SaveChanges();
                    }

    3 未给主键赋值或赋给主键一个不存在的值,抛出异常

    System.Data.Entity.Infrastructure.DbUpdateConcurrencyException

    操作代码如下,其中Id=1这条语句被注掉,Id是主键:

                using (CustomDbContext db = new CustomDbContext())
                    {
                        User user = new User 
                        {
                            //Id = 1,
                            Email = "test@132.com",
                        };
                        DbEntityEntry<User> entry = db.Entry<User>(user);
                        entry.State = EntityState.Unchanged;
                        entry.Property(t => t.Email).IsModified = true;
                        int num = db.SaveChanges();
                    }    

    运行上述代码,抛出异常信息如下,注意异常类型居然是System.Data.Entity.Infrastructure.DbUpdateConcurrencyException,看上去像是并发问题,但实际却不是!

    Message:

    Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.

    赋给主键一个不存在的值,令Id=4(在数据库表中不存在Id为4的一条记录)抛出的异常与上面的相同。

    4 字段超长抛出异常:System.Data.Entity.Validation.DbEntityValidationException

    表中Nickname 字段定义为50个字符,现在赋值超过50。

    操作代码如下:

    using (CustomDbContext db = new CustomDbContext())
                    {
                        User user = new User
                        {
                            Id = 4,
                            Email = "test@132.com",
                            Nickname = "TestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateError"
                        };
                        DbEntityEntry<User> entry = db.Entry<User>(user);
                        entry.State = EntityState.Unchanged;
                        entry.Property(t => t.Email).IsModified = true;
                        int num = db.SaveChanges();
                    }

    运行程序报错:

    一层一层点开,查看具体原因:

     -----------------------------------------------------------------------------------------

    转载与引用请注明出处。

    时间仓促,水平有限,如有不当之处,欢迎指正。

  • 相关阅读:
    golang模拟动态高优先权优先调度算法
    【2019腾讯暑期实习生正式批笔试1,2】
    golang优先队列
    git常见操作
    小L的试卷
    Unable to connect to the Redgate Client Service. Sql Prompt 报错不能用解决
    未能加载文件或程序集“Microsoft.VisualStudio.Enterprise.AspNetHelper, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”或它的某一个依赖项。系统找不到指定的文件。
    LumiSoft 邮件操作删除(无法删除解决方法)
    .net MVC 项目中 上传或者处理进度获取方案
    C# mvc Request 请求过长报404错误的解决思路分析
  • 原文地址:https://www.cnblogs.com/hdwgxz/p/7897031.html
Copyright © 2020-2023  润新知