本文介绍EntityFramework使用方法

  1. Entity Framework的注意点

    由于安装和操作的细节讲起来很琐碎,这部分只罗列出难点,其他细节请自行查阅
    安装细节
    Pluralize or singularize generated object names(确定所生成对象名称的单复数形式)复选框
    此复选框的意思是,将数据库中的复数表名映射成单数形式的实体类,如果有一对多,多对多关系的表会将属性名以复数形式显示,增加程序可读性
    Include foreign key columns in the model (在模型中包含外键)复选框
    将数据库外键关系映射到实体模型中
    Import selected stored procedures and functions into entity model (将所选存储过程和函数导入到实体模型中)
    将存储过程和函数导入到实体模型
    操作CRUD
    要先实例化上下文类
    using(var ctx = new SchoolDBEntities())
    {
    // 进行增删改查
    }
  2. 支持的查询方法

    支持的查询数据的方式有
    LINQ to Entites
    linq方法
    var linq = ctx.Students.Where(s => s.StudentID > 2);
    linq查询语句
    var linq = from item in ctx.Students select item;
    Entity SQL
    此法不建议使用
    Native SQL
    var tempResult = ctx.Students.SqlQuery("select * from Student");
    注意:sql语句返回的列不能改名,否则报错
    返回值类型的写法
    string result = db.Database.SqlQuery<string>("select studentname from Student where studentid = 1").FirstOrDefault<string>();
    执行非查询sql的写法
    int noOfRowUpdated = ctx.Database.ExecuteSqlCommand("Update student set studentname ='changed student by command' where studentid=1");
  3. ef表示体包含的方法

    ctx.Students表实体中除了上面讲到的SqlQuery方法外还包括如下方法
    Add方法
    db.Students.Add(student); // 添加一条记录到实体框架中
    AsNoTracking方法
    如果查询的数据只是用来展示的,可以使用AsNoTracking方法将查询的数据和DbContext断开连接,提高查询效率
    var result = db.Students.Select(s => new
    {
    s.StandardId,
    s.StudentName
    }).AsNoTracking().ToList();
    Attach方法
    将一条Student数据附加到EF的跟踪图中就像数据是从数据库中读取的一样,其实数据库中并不存在
    var result = db.Students.Attach(st);
    Create方法
    创建一个空的Student实例,该实例没有附加到Students集合中
    var result = db.Students.Create();
    Find方法
    返回Students表中主键id是5的数据,与之关联的数据也会一起返回
    如果数据已经添加到上下文中,但是没有保存到数据库,使用Find同样有效
    var result = db.Students.Find(5);
    Include方法
    指定包含在结果集中的导航属性
    var result = db.Students.Include("StudentAddress").ToList<Student>();
    也可以传递lambda表达式
    var result = db.Students.Include(s => s.Standard).ToList<Student>();
    Remove方法
    将提供的Student实例标记为已删除,改实例必须存在于上下文中
    var result = db.Students.Remove(st);
    SqlQuery带参数的用法
    var result = db.Students.SqlQuery("select * from student where studentid = @p", new SqlParameter("@p", SqlDbType.Int) { Value = 5} ).Select(s => s.StudentName).ToList();
  4. DBEntityEntry对象

    ef实体框架中,可以通过数据实体获取数据实体相关的DBEntityEntry对象,从而得到数据实体的所有信息
    var student = db.Students.Find(1);
    student.StudentName = "yejiawei";
    var entry = db.Entry(student); // 获取数据实体的DBEntityEntry对象
    属性
    var result = entry.Entity.GetType().FullName; // 获取实体的名称
    var result = entry.State.ToString(); // 获取实体当前的状态
    IEnumerable<string> result = entry.CurrentValues.PropertyNames; // 获取实体的所有属性名
    var result = entry.OriginalValues["StudentName"]; // 获取实体属性修改之前的值
    var result = entry.CurrentValues["StudentName"]; // 获取实体属性修改之后的值
    可以手动设置实体的状态为 Added,Modified,Deleted
    entry.State = EntityState.Modified;
    方法
    Collection
    返回导航属性的集合,多对多关系
    var result = entry.Collection("Courses");
    可以继续使用 result.Load() 预载数据
    还可以继续使用 result.Query().Where(...) 进一步筛选数据
    ComplexProperty
    返回复杂属性的集合
    GetDatabaseValues
    返回跟踪的属性集合
    var result = entry.GetDatabaseValues();
    Property
    返回实体指定属性的所有信息组成的集合
    var result = entry.Property("StudentName");
    Reference
    返回导航属性的集合,一对多或者多对一关系
    var result = entry.Reference("StudentAddress");
    可以继续使用 result.Load() 预载数据
    还可以继续使用 result.Query().Where(...) 进一步筛选数据
    Reload方法
    entry.Reload();
    调用此方法,之前的所有更改都无效,全部和数据库同步,并且当前状态是Unchanged
  5. 追踪变化

    在ef上下文的生命周期中,ef会自动追踪加载进来的实体,可以通过ChangeTracker来获取所有被上下文追踪的实体
    每一个实体都必须包含一个主键,如果没有主键ef是不会追踪的
    var student = db.Students.Find(1);
    属性
    var result = db.ChangeTracker.Entries(); // 获取所有被上下文追踪的实体
    var result = db.ChangeTracker.Entries().Count(); // 获取所有被上下文追踪的实体的个数
    var result = db.ChangeTracker.Entries(); // 获取当前上下文中的所有DBEntityEntry对象对象
  6. 维持Entity Framework的实体场景

    连接场景
    数据检索和增删改都在一个上下文里面操作
    在连接场景中完成增删改查是非常容易的,因为上下文自动跟踪实体的状态,AutoDetectChangesEnabled默认是true
    添加操作
    定义一个引用类型比较类
    public class StudentComparer : IEqualityComparer<Student>
    {
    public bool Equals(Student x, Student y)
    {
    if (x.StudentName.ToLower() == y.StudentName.ToLower())
    {
    return true;
    }
    return false;
    }
    public int GetHashCode(Student obj)
    {
    return obj.GetHashCode();
    }
    }
    新增操作
    if(!db.Students.ToList().Contains(new Student() { StudentName = "yejiawei" }, new StudentComparer()))
    {
    db.Students.Add(new Student() { StudentName = "yejiawei" });
    db.SaveChanges();
    return Ok("添加成功");
    }
    return Ok("已经存在了");
    修改操作
    Student StudetUpdate = db.Students.ToList().Where(s => s.StudentName == "yejiawei").FirstOrDefault();
    StudetUpdate.StudentName = "叶家伟";
    db.SaveChanges();
    删除操作
    db.Students.Remove(db.Students.ToList().ElementAt(0));
    db.SaveChanges();
    断开连接场景
    数据检索和增删改在不同的上下文里面操作
    在断开连接场景中,我们需要附加实体到新的上下文中,并且要指定状态
    Add方法,会自动的将实体块附加到新的上下文中并且自动的修改状态为Added,也就是说你调用Add方法,管他啥玩意儿都可以成功
    Attach方法,调用Attach方法会将实体块添加到上下文中,但是状态还是Unchanged,需要手动设置
    var test = db.Students.Attach(new Student() { StudentName = "yejiawei" });
    db.Entry(test).State = EntityState.Added;
    var result = db.Entry(test).State.ToString();
    db.SaveChanges();
    单个的实体
    单个的实体,直接更改状态,然后保存即可
    var test = new Student() { StudentName = "叶家伟" };
    db.Entry(test).State = EntityState.Added;
    var result = db.Entry(test).State.ToString();
    db.SaveChanges();
  7. Entity Framework并发问题

    在ef中可以根据数据库timestamp类型的列来处理并发问题,timestamp数据会在插入和更新时自动更改并且是唯一的
    数据库中timestamp类型的值是自动添加的
    然后,需要在ef中将timestamp列属性中的Concurency Mode设置为Fixed
    此时,ef在执行更新操作会将timestamp列设置成where的字句,来判断操作的数据有没有并发操作,如果发生了并发操作,那么会抛出DbUpdateConcurrencyException错误
    Student test1 = null;
    using(var context1 = new SchoolDBEntities())
    {
    context1.Configuration.ProxyCreationEnabled = false; // 查询的时候是否包含导航属性
    test1 = context1.Students.Where(s => s.StudentID == 9).Single();
    test1.StudentName = "小王";
    try
    {
    context1.Entry(test1).State = EntityState.Modified;
    context1.SaveChanges();
    }
    catch (DbUpdateConcurrencyException ex)
    {
    var t = ex;
    }
    }
  8. 执行存储过程

    如下的存储过程导入到ef中
    ALTER PROCEDURE [dbo].[GetCoursesByStudentId]
    -- Add the parameters for the stored procedure here
    @StudentId int = null
    AS
    BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    -- Insert statements for procedure here
    select c.courseid, c.coursename,c.Location, c.TeacherId
    from student s left outer join studentcourse sc on sc.studentid = s.studentid left outer join course c on c.courseid = sc.courseid
    where s.studentid = @StudentId
    END
    然后直接当做函数执行就可以了
    var courses = db.GetCoursesByStudentId(1);
    可以将更新,删除,新增的存储过程映射到实体上面,从而重写ef默认的增删改的方法
    存储过程中,新增的时候执行SELECT SCOPE_IDENTITY() AS StudentId,可以返回新增数据的id
  9. 在ef中使用枚举

    数据库中可以使用一些特殊的整数值,来表示数据的特殊含义,为了是代码的可读性更强,使用枚举来代替这些整数值
    首先,将实体中的一个属性列,Convert to Enum
    然后,在弹出的选择框中,输入枚举类型的名字,也就是你在写代码时要用到的枚举名称
    其次,在成员列表中,指定成员的名字,和成员对应的整数值
    现在,你可以使用你定义的枚举了
    var type = TeacherType.Guest;
  10. 在ef中使用表值函数

    首先要在数据库中添加一个表值函数
    ALTER FUNCTION [dbo].[GetCourseListByStudentID]
    (
    -- Add the parameters for the function here
    @studentID int
    )
    RETURNS TABLE
    AS
    RETURN
    (
    -- Add the SELECT statement with parameter references here
    select c.courseid, c.coursename,c.Location, c.TeacherId
    from student s left outer join studentcourse sc on sc.studentid = s.studentid left outer join course c on c.courseid = sc.courseid
    where s.studentid = @studentID
    )
    然后将这个表值函数导入到ef中,可以在模型浏览器中修改函数,然后在ef中使用表值函数,如下
    var result = db.GetCoursesByStudentId(1).Select(s => s);
  11. Local属性

    可以通过Local属性访问当前被追踪的实体,被标记为Deleted的实体不可以通过Local访问
    db.Students.Load(); // 预载,免去写ToList
    db.Students.Add(new Student() { StudentName = "New Student" });
    return Ok(db.Students.Local);
  12. 预先加载

    使用Include,表示加载导航属性
    (from s in context.Students.Include("Standard")
    where s.StudentName == "Student1"
    select s).FirstOrDefault<Student>();
  13. 懒加载

    当实体中包含包含复杂属性,只有当访问这个复杂属性的时候才会去查询
    如果要为整个上下文关闭懒加载,可以在上下文的类中设置
    public SchoolDBEntities(): base("name=SchoolDBEntities")
    {
    this.Configuration.LazyLoadingEnabled = false;
    }
    如果想只关闭某一个属性的懒加载,可以导实体的类中设置
    public virtual StudentAddress StudentAddress { get; set; }将这个virtual关键字去掉即可
  14. 异步查询和保存

    异步查询
    使用async标记此方法是异步的
    public async Task<Student> GetStudents()
    {
    Student result = null;
    using (var context = new SchoolDBEntities())
    {
    context.Configuration.ProxyCreationEnabled = false;
    // 使用await,可以释放当前线程从而可以执行其他代码,避免阻塞程序
    result = await context.Students.Where(s => s.StudentID == 10).FirstOrDefaultAsync<Student>();
    }
    return result;
    }
    异步保存
    public async Task<int> Get()
    {
    using (var context = new SchoolDBEntities())
    {
    var test = context.Courses.Attach(new Course() { CourseName = "数学" });
    context.Entry(test).State = EntityState.Added;
    return await context.SaveChangesAsync();
    }
    }
  15. 日志的记录

    第一种方式,使用默认配置
    在web.config配置文件中的entityFramework节点下添加
    <interceptors>
    <interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework">
    <parameters>
    <parameter value="F:\学习实验区\EntityFramework\Log.txt"/>
    <parameter value="true" type="System.Boolean"/>
    </parameters>
    </interceptor>
    </interceptors>
    即可自动的记录ef做的所有操作
    第二种方式,自定义日志记录
    using (var context = new SchoolDBEntities())
    {
    // 使用Log方法即可自动实现记录日志,然后追加到日志文件中
    context.Database.Log = (string message) =>
    {
    byte[] bts = Encoding.UTF8.GetBytes(message);
    using (FileStream fwrite = File.OpenWrite(@"F:\学习实验区\EntityFramework\Log1.txt"))
    {
    //fwrite.Write(bts, 0, bts.Length);
    fwrite.Position = fwrite.Length;
    fwrite.Write(bts, 0, bts.Length);
    }
    };
    var test = context.Courses.Attach(new Course() { CourseName = "数学" });
    context.Entry(test).State = EntityState.Added;
    return await context.SaveChangesAsync();
    }
  16. 事务提交和回滚

    ef默认的操作都是事务处理的,但是我们可以将ef多个操作再用一个事务封装起来,方便回滚
    using(DbContextTransaction dbTran = context.Database.BeginTransaction())
    {
    try
    {
    var test = context.Courses.Attach(new Course() { CourseName = "333" });
    context.Entry(test).State = EntityState.Added;
    await context.SaveChangesAsync();
    dbTran.Commit();
    return 1;
    }catch(Exception ex)
    {
    dbTran.Rollback();
    return 0;
    }
    }
  17. AddRange和RemoveRange

    AddRange批量增加
    List<Course> list = new List<Course>()
    {
    new Course() { CourseName = "yuwen" },
    new Course() { CourseName = "shuxue" },
    new Course() { CourseName = "yinyu" }
    };
    using (var context = new SchoolDBEntities())
    {
    context.Courses.AddRange(list);
    return await context.SaveChangesAsync();
    }
    RemoveRange批量删除
    using (var context = new SchoolDBEntities())
    {
    var items = context.Courses.Where(
    s => s.CourseName == "yuwen" || s.CourseName == "shuxue" || s.CourseName == "yinyu"
    ).AsEnumerable<Course>();
    context.Courses.RemoveRange(items);;
    return await context.SaveChangesAsync();
    }

最新文章

  1. treeview 控件使用和数据绑定
  2. SQLServer : EXEC和sp_executesql的区别
  3. jquery实现内容滚动
  4. CSU 1113 Updating a Dictionary(map容器应用)
  5. 重新想象 Windows 8.1 Store Apps (90) - 通信的新特性: 通过 HttpBaseProtocolFilter 实现 http 请求的缓存控制,以及 cookie 读写; 自定义 HttpFilter; 其他
  6. Inside of Jemalloc
  7. 手机站点开发及手机中图片加速显示img的Canvas方法
  8. XCODE 控件连接(关联)不上变量 怎么解决
  9. POJ1113 Wall 凸包
  10. ES6(Decorator(修饰器))
  11. cellmap 基站查询 for android
  12. 2019-04-15-day032-多进程介绍
  13. 使用 Immutable Subject 来驱动 Angular 应用
  14. MT【72】一个不等式
  15. ORGANISING THE TEST CASES
  16. feign调用接口session丢失解决方案
  17. 正则表达式/(^\s*)|(\s*$)/g意思
  18. python标准库介绍——21 UserDict 模块详解
  19. POJ 2251 Dungeon Master (三维BFS)
  20. kvm初体验之四:从Host登录Guest的五种方式

热门文章

  1. 【转】服务器.htaccess 详解以及 .htaccess 参数说明
  2. 【转】Android ImageView圆形头像
  3. 回溯法之n皇后问题
  4. UOJ66 新年的巧克力棒
  5. Swagger自动生成接口文档
  6. 阿里云 linux 找回mysql root密码
  7. html5学习(新增元素)
  8. 浅谈如何优化SQL Server服务器
  9. MRC与ARC混合编程的编译器标记
  10. Maven下载 || 配置本地仓库 || IntelliJ IDEA配置Maven教程