1. 程式人生 > >Entity Framework——常見報錯總結

Entity Framework——常見報錯總結

container mysq 詳細 exceptio 並發 ner req 相同 ()

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 = "[email protected]",
                    };
                    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 = "[email protected]",
                        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 = "[email protected]",
                    };
                    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 = "[email protected]",
                    };
                    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 = "[email protected]",
                    };
                    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 = "[email protected]",
                    };
                    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 = "[email protected]",
                        Nickname = "TestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateErrorTestUpdateError"
                    };
                    DbEntityEntry<User> entry = db.Entry<User>(user);
                    entry.State = EntityState.Unchanged;
                    entry.Property(t => t.Email).IsModified = true;
                    int num = db.SaveChanges();
                }

運行程序報錯:技術分享圖片

一層一層點開,查看具體原因:技術分享圖片

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

轉載與引用請註明出處。

時間倉促,水平有限,如有不當之處,歡迎指正。

Entity Framework——常見報錯總結