zoukankan      html  css  js  c++  java
  • 【EF】知识笔记

    一、EF更新数据库字段的三种方法

      实体类

       public class TestDbContext : DbContext
        {
            public DbSet<Test> Tests { get; set; }
            public TestDbContext() : base() { }
        }
        public class Test
        {
            public long ID { get; set; }
            public string Name { get; set; }
            public string Email { get; set; }
            public string Remarks { get; set; }
        }

    创建数据

                TestDbContext db = new TestDbContext();
                db.Tests.Add(new Test() { Name = "测试1", Email= @"123@abc.com", Remarks = "测试1备注"});
                db.Tests.Add(new Test() { Name = "测试2", Email = @"456@abc.com", Remarks = "测试2备注"});
                db.SaveChanges();

    第一种方法:

      先查询记录,然后修改相应的属性。此方法虽然多了一个查询步骤,但是也由此利用了EF的自动跟踪功能,后续操作比较方便。

    比如,生成的SQL语句只会去修改相应的修改过的字段。

    而且经测试发现,如果实体属性值没有改变,不会生成SQL语句,比如将下面的代码执行两次,第二次 SaveChanges() 方法不会执行SQL更新语句(注:由于还是会执行一次查询,所以运行效率并没有显著提升)

    TestDbContext db = new TestDbContext();
    var test = db.Tests.Find(1);
    test.Remarks = "更新字段方法1";
    db.SaveChanges();

    第二种方法:

      直接创建一个新的实体类,然后修改实体对象的状态。此方法虽然少了一个查询步骤,但生成的SQL语句将会修改全部字段,而且还要确保 ID 值存在。(注意:由于会修改全部字段,没有设置的字段会被设置为null

    TestDbContext db = new TestDbContext();
    Test test = new Test() { ID = 1, Remarks = "更新字段方法2" };
    db.Entry(test).State = System.Data.Entity.EntityState.Modified;
    db.SaveChanges();   

    第三种方法:

      创建一个实体类,将实体附加到数据库上下文,然后修改相应属性值的修改标识为 true ,此方法生成的SQL语句与第一种方法一样,比较简洁,而且还少了查询步骤,只是后续的操作比较麻烦,因为要手动设置各个属性的修改标识,还要确保 ID 值存在。

     TestDbContext db = new TestDbContext();
                Test test = new Test() { ID = 1, Remarks = "更新字段方法3" };
                db.Tests.Attach(test);
                db.Entry(test).Property("Remarks").IsModified = true;
                db.SaveChanges();

    生成的SQL语句(使用 SQL Server Profiler 跟踪数据库所得):
    第一种方法:(注:第一种方法的代码执行一次后再次执行没有跟踪到更新数据库的SQL语句)

    exec sp_executesql N‘UPDATE [dbo].[Tests]
    SET [Remarks] = @0
    WHERE ([ID] = @1)
    ‘,N‘@0 nvarchar(max) ,@1 bigint‘,@0=N‘更新字段方法1‘,@1=1

    第二种方法:(注:查看SQL语句可知,使用此方法如果不注意可能会导致数据被错误修改

    exec sp_executesql N‘UPDATE [dbo].[Tests]
    SET [Name] = NULL, [Email] = NULL, [Remarks] = @0
    WHERE ([ID] = @1)
    ‘,N‘@0 nvarchar(max) ,@1 bigint‘,@0=N‘更新字段方法2‘,@1=1

    第三种方法

    exec sp_executesql N‘UPDATE [dbo].[Tests]
    SET [Remarks] = @0
    WHERE ([ID] = @1)
    ‘,N‘@0 nvarchar(max) ,@1 bigint‘,@0=N‘更新字段方法3‘,@1=1

    二、EF添加记录时获取自增ID值

      Entity Framework在将数据插入数据库时,如果主键字段是自增标识列,会将该自增值返回给实体对象对应的属性。

    比如下面添加博客随笔至数据库的示例代码:

    var blogPost = new BlogPost()
    {
        Author = "博客园",
        Title = "程序员的网上家园"
    };
    using (BlogDbContext context = new BlogDbContext())
    {
        context.BlogPosts.Add(blogPost);                
        context.SaveChanges();
        return blogPost.ID;
    }
    View Code

    SaveChanges()之后,blogPost.ID的值就是数据库中对应自增标识列的值

    看一下Entity Framework生成的SQL语句:

    exec sp_executesql N'insert [dbo].[blog_Content]([Title],[Author])

    values (@0, @1)

    select [ID]

    from [dbo].[blog_Content]

    where @@ROWCOUNT > 0 and [ID] = scope_identity()',

    N'@0 nvarchar(128),@1 nvarchar(128),',@0=N'程序员的网上家园',@1=N'博客园'

      EF通过scope_identity()获取自增列的值,而且我们没有对BlogPost的ID属性进行任何设置,是EF智能地判断出ID就是自增标识列

    在以前没有使用Entity Framework的时代,用的是存储过程,存储过程有一堆参数,实体对象的属性值要一一对应地赋值给这些参数,执行存储过程之后,还要通过ParameterDirection.Output的参数获取自增ID的值。

    三、EF中 一例对一个或多个实体的验证失败。有关详细信息,请参阅“EntityValidationErrors”属性的解决

      注:add数据时 最好加异常捕获(以防一些必填字段没有赋值)

    这个问题相信只要是做MVC的,都碰到过,也都知道错误的原因,就是触发了定义的实例字段校验规则。比如定义的不为空,但是为空了,或者定义的字段长度为50,但是超过50了。

    可是有时虽然知道是这样,但是具体问题解决的时候还是无从下手。我最近就碰到一个,知道是在更新某个表的时候出现的这个问题。可是在本地无法具现此错误,这个错误是在特定条件发生的,我并不知道此特定发生条件是什么,很郁闷。

    在网上找了下,知道发生这个错误会触发DbEntityValidationException异常,这个异常会有详细的异常信息说明是哪个字段,出现了什么错误,只不过需要循环输出。打算输出到日志文件中看是什么错误。代码如下:

    try
                {
                    es2.Update(examList);
                }
                catch (DbEntityValidationException dbEx)
                {
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                    {
                        foreach (var validationError in validationErrors.ValidationErrors)
                        {
    
                            EventLog.Log(string.Format("Class: {0}, Property: {1}, Error: {2}", validationErrors.Entry.Entity.GetType().FullName,
                            validationError.PropertyName,
                            validationError.ErrorMessage), "error");
                        }
                    }
    
                }
                catch (Exception ex)
               {
                    throw;
                }
    finally
                {
                }
    View Code

    之所以用2个catch,是为了防止有其他非DbEntityValidationException 错误时,没有错误日志。

    DbEntityValidationException所在命名空间:System.Data.Entity.Validation

    编译,上传到服务器,过了一会,查看日志文件,找到错误原因了。

     Class: System.Data.Entity.DynamicProxies.ExamList_839A196D8FC4CF7E8A791B7F29782BA535E73532A1C3C2C00FD6EF30B6C4A660, Property: StudentAnswer, Error: 字段 StudentAnswer 必须是最大长度为 50 的字符串。
    是StudentAnswer 字段长度不够了。

  • 相关阅读:
    POJ 2411 Mondriaan's Dream
    POJ 2505 A multiplication game
    HDOJ(HDU) 3949 XOR
    雅礼集训DAY 6 T1 xmasdag
    bzoj 2159: Crash 的文明世界
    如何查看Ubuntu版本
    Ubuntu如何安装谷歌Chrome浏览器
    使用nano编辑器进行查找和替换
    Ubuntu修改用户和root密码
    Anaconda/Conda创建环境时报错的解决方案
  • 原文地址:https://www.cnblogs.com/peterYong/p/9756854.html
Copyright © 2011-2022 走看看