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

运行程序报错:

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

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿天地

spring-data-mongodb之MongoTemplate 添加数据

来源:猿天地 链接:http://cxytiandi.com/blog/detail/1733 今天我们来学习下MongoTemplate的添加数据操作,大神请...

3699
来自专栏Ryan Miao

Spring resource bundle多语言,单引号format异常

Spring resource bundle多语言,单引号format异常 source code 前言 十一假期被通知出现大bug,然后发现是多语言翻译问题。...

3318
来自专栏偏前端工程师的驿站

编译期类型检查 in ClojureScript

872
来自专栏技术小讲堂

WCF中数据契约之已知类型的几种公开方式代码中定义配置中定义宿主端使用解析器

WCF中传输的数据不想传统的面向对象编程,它只传递了一些对象的属性,但是自身并不知道自己属于什么对象,所以,他没有子类和父类的概念,因而也就没有Is-a的关系,...

2693
来自专栏面朝大海春暖花开

spring配置多数据源——mybatis

这篇文章是配置mybatis多数据源文章,如果是hibernate的话也是没什么影响,配置都是差不多的。

952
来自专栏企鹅号快讯

我们来继续研究 mybatis 框架sql映射文件的属性

温馨提示:本问阅读需要4分钟,建议收藏后阅读! 各位小伙伴 祝大家元旦快乐 开始我们今天的分享 我们已经了解了 mybatis 框架的两种使用方式以及主配置文件...

18410
来自专栏学习力

《Java从入门到放弃》JavaSE篇:练习——单身狗租赁系统(数组版)

1916
来自专栏静默虚空的博客

Dozer 使用小结

这篇文章是本人在阅读Dozer官方文档(5.5.1版本,官网已经一年多没更新了)的过程中,整理下来我认为比较基础的应用场景。 本文中提到的例子应该能覆盖Java...

3557
来自专栏偏前端工程师的驿站

编译期类型检查 in ClojureScript

前言  话说"动态类型一时爽,代码重构火葬场",虽然有很多不同的意见(请参考),但我们看到势头强劲的TypeScript和Flow.js,也能感知到静态类型在某...

1777
来自专栏青枫的专栏

java中的类型安全问题-Type safety: Unchecked cast from Object to ... 或者 Type safety: Unchecked cast from Type

首先,java语言室类型安全的,通常我们遇到这个问题是出现在 Object转化为目标类型 或者 Type转化为目标类型 时,

502

扫码关注云+社区