EntityFramework 6学习笔记

EntityFramework 6学习笔记

  1. 来自数据库的EF设计器(DBFirst)

    1. 解释:根据已经设计好的数据库,来生成操作模型对象。
  2. 空的EF设计模型

    1. 解释:创建一个空的EDM实体数据模型工具,通过在EDMX文件中建立模型对象来生成数据库和操作对象。
  3. 空的CodeFirst模型

    1. 解释:通过代码建立实体对象模型,生成数据库。
  4. 来自数据库的CodeFirst

    1. 解释:根据已经设计好的数据库为模型,生成操作对象和数据库上下文。
  5. EF的导航属性和跟踪管理机制

    1. EF导航数据:外键被称为导航属性,映射出该表与导航属性表的关系。通过导航数据可以用来查询和延迟加载。

    2. 跟踪机制:通常都是通过调用SaveChanges方法把增加/修改/删除的数据提交到数据库。但是上下文是如何知道实体对象是增加、修改是通过EntityState的枚举值来判断的。

    3. EntityState状态

      1. Detached:对象存在,但未由对象服务跟踪。在创建实体之后、但将其添加到对象上下文之前,该实体处于此状态;(已分离:上下文未跟踪该实体)

      2. Unchanged:自对象加载到上下文中后,或自上次调用 System.Data.Objects.ObjectContext.SaveChanges() 方法后,此对象尚未经过修改;(保持不变:上下文正在跟踪实体,该实体存在于数据库中,并且其属性值未更改为数据库中的值)

      3. Added:对象已添加到对象上下文,但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法;(已添加:上下文正在跟踪实体,但数据库中尚不存在该实体)

      4. Deleted:使用 System.Data.Objects.ObjectContext.DeleteObject(System.Object) 方法从对象上下文中删除了对象;(已删除:实体正在由上下文跟踪,并存在于数据库中,但在下次调用 SaveChanges 时已标记为要从数据库中删除)

      5. Modified:对象已更改,但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法。(已修改:实体正在由上下文跟踪,并存在于数据库中,并且其部分或全部属性值已修改)

      6. https://docs.microsoft.com/zh-cn/ef/ef6/saving/change-tracking/entity-state?redirectedfrom=MSDN

      7. Attach

        1. Attach:将一个处于Detached的Entity附加到上下文,而附加到上下文后的这一Entity的State为UnChanged。
        2. 在上面的程序中通过调用Attach()方法只能把对象添加到了对象上下文中(此时对象的状态已经是Unchanged的),如果执行附加实体的任何其他操作, 执行SaveChange()方法并不能真正添加到数据库中去,不会对数据库进行任何更改。 这是因为实体处于未更改状态。
    4. 插入或更新模式插入或更新模式

      1. 可以通过基于主键值的检查设置实体状态来实现此模式,通常将包含零键的实体作为新的和具有非零键的实体视为现有的。
      2. context.Entry(blog).State = blog.BlogId == 0 ? EntityState.Added :EntityState.Modified;
    5. EF查询优化

      1. 查询优化

        1. 取消跟踪
          1. AsNoTracking()
          2. db.Configuration.AutoDetectChangesEnabled = false;
          3. 查询条件,带着变量(变量将会变成参数)效率提高
      2. 修改优化

        1. 普通方式:先查找对象,在根据查找的对象修改对象,最后保存数据库
        2. 直接new一个字段,设置上下文状态,保存数据库。比普通方式少了一个查询操作。
        1. /*查询状态跟踪*/
           /*
            * 方式一
            * AsNoTracking()
            */
           var students= db.Students.ToList();
           var studentsNoTracking=db.Students.AsNoTracking().ToList();
            db.Configuration.AutoDetectChangesEnabled = false;
                          
          /*
           *修改对象
           * 优化查询
           * 需要注意,非空的字段都得写出来
           */
          
          Students stu = new Students
          {
              StudentAddress = "2222",
              StudentName = "wan",
              StudentIdNo = 130223198910111228,
              ClassId = 2,
              Gender = "男",
              Birthday = Convert.ToDateTime("1990-10-11"),
              Age = 24,
              PhoneNumber = "88888888",
              StudentId = 100013
          };
          db.Entry<Students>(stu).State = System.Data.Entity.EntityState.Modified;
          db.SaveChanges();
          
          /*
           *删除对象
           */
          //将主键值封装到要删除的对象中
          Students stu = new Students { StudentId = 100014 };
          using (EFDBEntities efdb = new EFdemo.EFDBEntities())
          {
              efdb.Set<Students>().Attach(stu);
              efdb.Entry(stu).State = System.Data.Entity.EntityState.Deleted;
          
              Console.WriteLine(efdb.SaveChanges());
          }
          
          
          
      3. 使用本地查换成查询

        1. 注意事项:如果查询结果没有缓存到本地,是无法获取数据的。例如

        2. accounts.FirstOrDefault();
           Console.WriteLine("数据库真实的用户数据:{0}", context.Accounts.Count());
           Console.WriteLine("只能读取到一条数据,因为FirstOrDefault()只缓存一条:{0}", context.Accounts.Local.Count());
          
        3. using (EFDBEntities efdb = new EFDBEntities())
          {
            var stuList = from stu in efdb.Students select stu;
             foreach (var item in stuList)
             {
              	 Console.WriteLine(item.StudentId + "\t" + item.StudentName);
             }
            //查询学生总数
            Console.WriteLine("学生总数:{0}", efdb.Students.Count());
            //使用缓存查询学生总数
            Console.WriteLine("学生总数:{0}", efdb.Students.Local.Count());
            Console.ReadLine();
          }
          
  6. EF的事务

    1. 在查询时没有事务,在增删改时EF会默认开启事务。

    2. 自定义事务

      1. 自定义事务可以在某些时候改变事务隔离级别(System.Data.IsolationLevel)7种

      2. 默认隔离级别:Read Commit

      3. 实现ReadUncommitted的2种方式(可以进行脏读,意思是说,不发布共享锁,也不接受独占锁。)

        /*方式一*/ 
        using (var cusTransaction = db.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
          {
              try
              {
                  db.Database.Log = Console.WriteLine;
                  //我们可以在这个地方添加需要的增删改操作...
        
                  db.StudentClass.Add(new StudentClass { ClassId = 35, ClassName = ".NET高级学习班5" });
                  db.StudentClass.Add(new StudentClass { ClassId = 36, ClassName = ".NET高级学习班6" });
        
                  db.SaveChanges();
        
                  cusTransaction.Commit();
        
              }
              catch (Exception ex)
              {
                  cusTransaction.Rollback();
                  throw ex;
              }
          }
        
        /*方式二*/
        
         using (var cusTransaction = new TransactionScope())
         {
            try
            {
                db.Database.Log = Console.WriteLine;
                //我们可以在这个地方添加需要的增删改操作...
        
                db.StudentClass.Add(new StudentClass { ClassId = 45, ClassName = ".NET高级学习班11" });
                db.StudentClass.Add(new StudentClass { ClassId = 46, ClassName = ".NET高级学习班10" });
        
                db.SaveChanges();
        
                cusTransaction.Complete();
        
            }
            catch (Exception ex)
            {
                Transaction.Current.Rollback();
                throw ex;
            }
         }
        
  7. EF查询的三种加载模式

    1. 延迟加载

      1. 延迟加载是当需要用到数据时,才会进行加载查询,同时会根据主外建生成的导航属性进行查询。

      2.   var student = db.Students.FirstOrDefault();
        /*
         * 1、首先进行查询,返回一个SqlDataReader对象(Student对象)此时结果已经出来了(直接取除导航属性外的值不会进行二次查询),如果展开,因为这个类有导航属性。
         * 2、展开后对2个外键进行查询(班级和成绩)
         * 3、展开班级外键,在student表查询班级是这个的结果(因为班级关联多个Student对象)
         * 结论:延迟查询可以对关联的导航属性进行查询。
         */
        
      3. 关闭延迟加载:关闭延迟加载后不会对导航属性进行查询

        1. db.Configuration.LazyLoadingEnabled = false;
    2. 显示加载

      1. 对于已经关闭的延迟加载,我们可以再次手动开启:db.Entry(student).Reference(s => s.StudentClass).Load();
    3. 立即加载

      1. 当我们获取一个实体对象的时候,与之关联的其他外键对象会被立即加载。
      2. var result = db.Students.Include(“StudentClass”).Include(“ScoreList”).ToList();
  8. EF-DBFirst使用存储过程

  9. 通过DataAnotation自定义字段

  10. FlunetAPI的使用

    1. EntityTypeConfiguration:提供了很多配置 实体或属性 的重要方法, 实现覆盖各种Code-First约定

      protected override void OnModelCreating(DbModelBuilder modelBuilder)
      {
          EntityTypeConfiguration<TEntity> tEntityCfg = modelBuilder.Entity<TEntity>();
          base.OnModelCreating(modelBuilder);
      }
      
      方法名返回类型描述
      HasKey<TKey>EntityTypeConfiguration为此实体配置主键属性
      HasMany<TTargetEntity>ManyNavigationPropertyConfiguration配置实体类型多对多关系
      HasOptional<TTargetEntity>OptionalNavigationPropertyConfiguration配置此实体类型的可选关系. 实体类型的实例可以保存到数据库,而不指定此关系. 数据库中的外键将为空.
      HasRequired<TTargetEntity>RequiredNavigationPropertyConfiguration配置此实体类型所需的关系. 实体类型的实例将无法保存到数据库,除非指定了该关系. 数据库中的外键将不可为空.
      Ignore<TProperty>Void从模型中排除属性,使其不会映射到数据库.
      MapEntityTypeConfiguration允许与实体类型映射到数据库模式的高级配置相关.
      Property<T>StructuralTypeConfiguration配置在此类型上定义的struct属性.
      ToTableVoid配置此实体映射到数据库的名称.

      https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.modelconfiguration.entitytypeconfiguration-1?redirectedfrom=MSDN&view=entity-framework-6.2.0

  11. CodeFirst数据库初始化策略

    1. Code First 中支持 4 种数据库初始化策略

      1. CreateDatabaseIfNotExists:这是默认的初始化程序。顾名思义,如果没有配置,它将创建数据库。但是,如果更改模型类,然后使用该初始化程序运行应用程序,那么它将抛出异常

      2. DropCreateDatabaseIfModelChanges:如果您的模型类(实体类)已更改,则此初始化程序将删除现有数据库并创建新数据库。因此,当您的模型类更改时,您无需担心维护数据库模式

      3. DropCreateDatabaseAlway:该初始化程序在每次运行应用程序时都会删除现有数据库,而不管您的模型类是否已更改。当您需要新鲜数据库时,每次运行应用程序时,就像在开发应用程序时一样

      4. Custom DB Initializer:您还可以创建自己的自定义初始化程序,如果上述任何一个都不满足您的要求,或者您想使用上述初始化程序初始化数据库的其他进程

                Database.SetInitializer<YourDBContext>(new CreateDatabaseIfNotExists<YourDBContext>());
                Database.SetInitializer<YourDBContext>(new DropCreateDatabaseIfModelChanges<YourDBContext>());
                Database.SetInitializer<YourDBContext>(new DropCreateDatabaseAlways<YourDBContext>());
                Database.SetInitializer<YourDBContext>(new YourDBInitializer());
        
        public class YourDBInitializer :  CreateDatabaseIfNotExists<YourDBContext>
        {
            protected override void Seed(YourDBContext context)
            {
                base.Seed(context);
            }
        }
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值