• 深入理解ADO.NET Entity Framework(02)


    目录:

    • ORM概念
    • 数据迁移
    • EF状态管理
    • 加载
    • 缓存
    • 事务
    • 封装EF的DAL层

    Ado.net Entity Framework 是Microsoft推出的ORM框架。

    1.ORM

    对象映射关系对数据库进行操作,解决面向对象与关系数据库不匹配的现象。

    • CSDL :概念层 O (对象)
    • SSDL :存储层 R(配置文件 标记对象对应数据库的表)
    • MSL :对应层 M (映射)

      EF包括三种模式:DBFirst、CodeFist、ModelFirst 。

       (1)数据库到对象模型

    • 在项目中添加"ADO.NET实体数据模型",选择"来自数据库的EF设计器",按照提示配置数据库相关信息。选择相关的数据库表。
    • 打开.emdx文件,edmx中包含SSDL、CSDL和C-S mapping三种类型的节点定义,分别对应EDM中的存储层、概念层、对应层。这也是EF实现ORM的关键配置文件。
    • 导航属性 -- 外键列 (一对一 (obj) 一对多(Icollection<obj>)) 
    • DBContext -- uisng system.data.Entity -- 数据库上下文
    • 操作数据
    //查询
    using (MySchoolEntities entities = new MySchoolEntities()){
    //按名称查询年级编号
    Grade grade = entities.Grade.SingleOrDefault(g => g.GradeName == "S2");
    if (grade!=null)
    Console.WriteLine("S2年级的编号为{0}",grade.GradeId);
    //用where()方法查询符合条件的数据
    IQueryable<Student> query = entities.Student.Where(s => s.GradeId == grade.GradeId);
    Console.WriteLine("学号	姓名");
    foreach (var stu in query)
    {Console.WriteLine("{0}	{1}",stu.StudentNo,stu.StudentName);}}
    
    //添加数据
    using (MySchool1Entities entities = new MySchool1Entities())
    {Student stu=new Student(){StudentNo="S10001",StudentName="王翱翔",GradeId=2,Sex=""};
    entities.Student.Add(stu); //向实体集添加数据
    if (entities.SaveChanges()>0) //将添加的数据保存到数据库中
    Console.WriteLine("添加数据成功!");}
    
    //修改数据
    using (MySchool1Entities entities = new MySchool1Entities()){
    //先查询要修改的数据
    Student stu = entities.Student.FirstOrDefault(s => s.StudentName == "王翱翔");
    if (stu!=null)
    {stu.LoginPwd = "123456"; //修改对象属性值}
    if (entities.SaveChanges()>0) //将修改的对象保存到数据库中
    {Console.WriteLine("修改数据成功!");}}
    
    //删除数据
    using (MySchool1Entities entities = new MySchool1Entities()){
    //先查询要删除的数据
    Student stu = entities.Student.FirstOrDefault(s => s.StudentName == "王翱翔");
    if (stu!=null)
    {entities.Student.Remove(stu);} //从数据集中移除数据if (entities.SaveChanges()>0)
    {Console.WriteLine("删除数据成功!");}}
    代码

    注意:需要额外做的两件事是创建数据上下文对象和调用其SaveChange()方法实现数据的增、删、改。

      (2)从代码到数据库

    • 安装Entity Framework package包、创建实体类、创建DbContext类、创建MySchoolContext类
    <configuration>
    <connectionStrings>
    <add name="MySchool" providerName="System.Data.SqlClient" connectionString="Data Source=.;Initial Catalog=Test;Persist Security Info=True;User ID=sa;Password=sa"/>
    </connectionStrings>
    </configuration>
    
    //创建MySchoolContext类
    sing System.Data.Entity;
    public class MySchoolContext:DbContext
    {
    //构造函数,会读取配置文件中的连接字符串
    public MySchoolContext():base("MySchool") //.config文件数据库连接字符串名称
    {}
    //对象集合
    public DbSet<Grade> Grade { get; set; }
    public DbSet<Student> Student { get; set; }
    //重新父类中的方法(当模型初始化后被调用)
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    //指定单数形式的表名(否则数据库的表名会是复数形式)
    //需要命名空间:using System.Data.Entity.ModelConfiguration.Conventions;
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
    }
    创建DbContext和MySchoolContext
    • EF中的默认约定

       关于表和字段名的约定。映射列和属性命名一致

       ②关于主键的约定。将命名为 Id 或 [类名]Id 的属性视为类的键,如果是int类型同时会设为标识列。

       ③字符串属性的约定。字符串约定为映射到不限长度的非空列中,默认数据类型为nvarchar(max),且允许为空。

       ④布尔值的约定。Code Frirst将bool属性映射为 bit 类型,且不允许为空。

       ⑤关系。1对1、1对多、多对多

    • 配置覆盖约定

        使用Data Annotation特性

    public class Student
    {
    
    [Key] //主键声明
    public string studentKey { get; set; }
    
    [Required] //非空声明
    public string stuName { get; set; }
    
    [MaxLength(10)] //最大长度
    public string stuTxt1 { get; set; }
    
    [MaxLength(10), MinLength(2)] //最大长度和最小长度
    public string stuTxt2 { get; set; }
    
    [ConcurrencyCheck] //并发检查
    public string stuTxt3 { get; set; }
    
    public virtual Address stuAddress { get; set; }
    }
    
    [ Table("myAddress")] //设置类映射的数据库表名
    public class Address
    {
    [ForeignKey("stu")] //设置外键(对应下面声明的 stu) //这里符合 类名+id(忽略大小写)的规则,所以自动生成主键
    public string AddressId { get; set; }
    
    [Column("myAddressName")] //设置映射数据库中表的列名
    public string AddressName { get; set; }
    
    [Column("myAddressName2", Order = 1, TypeName = "varchar")] //设置映射数据库中表的列名、顺序、类型
    
    public string AddrssName2 { get; set; }
    
    [NotMapped]//不映射数据
    public string addressNum { get; set; }
    
    public virtual Student stu { get; set; }
    }
    特性

        ②使用Fluent API

        可以将一个类映射成多个数据库表,还可以将配置写成多个文件,方便控制。优先级:Fluent API > data annotations > default conventions.

        常见配置:

          获取表对应的配置根: var stu =modelBuilder.Entity<XXX>();

          ❷设置主键:HasKey<string>(s => s.studentKey);

          ❸获取属性:stu.Property(p => p.stuName)

          ❹设置可空或非空:IsRequired和IsOptional

          ❺设置最大值:HasMaxLength

          ❻修改属性名→修改属性的次序→修改属性对应的数据库类型:HasColumnName→HasColumnOrder→HasColumnType

          ❼修改表名:ToTable

        可以建立多个Fluent API的配置文件,然后通过modelBuilder.Configurations.Add(new XXX());添加到一起。

    public class Student
    {
    //主键声明
    public string studentKey { get; set; }
    
    //非空声明
    public string stuName { get; set; }
    
    //最大长度
    public string stuTxt1 { get; set; }
    
    //最大长度和最小长度
    public string stuTxt2 { get; set; }
    
    //并发检查
    public string stuTxt3 { get; set; }
    }
    
    public class Address
    
    {
    //既是主键、又是外键
    public string AddressId { get; set; }
    
    //设置映射数据库中表的列名
    public string AddressName { get; set; }
    
    //设置映射数据库中表的列名、顺序、类型
    public string AddrssName2 { get; set; }
    
    //不映射数据
    public string addressNum { get; set; }
    
    }
    
    /// <summary>
    /// Game实体,与其它两个没有什么直接关系,单纯的为了演示, Fluent API的配置,可以根据实体进行拆分
    /// 文件来配置,方便管理
    /// </summary>
    public class Game
    {
    public int GameId { get; set; }
    public string GameName { get; set; }
    }
    
    /// <summary>
    /// Game实体的配置文件
    /// </summary>
    public class GameConfiguration : EntityTypeConfiguration<Game>
    {
    public GameConfiguration()
    {
    this.HasKey(p => p.GameId);
    this.Property(p => p.GameName).HasMaxLength(10).IsRequired();
    }
    }
    
    public class dbContext : DbContext
    {
    public dbContext(): base("name=MySchool")
    {
    }
       
    
    public DbSet<Student> Student { get; set; }
    
    public DbSet<Address> Address { get; set; }
    
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    //所有的FluentAPI均在方法中进行重写
    //一. 属性层次上的设置
    var stu = modelBuilder.Entity<Student>();
    var stuAddress = modelBuilder.Entity<StudentAddress>();
    
    //1. 设置主键
    stu.HasKey<string>(s => s.studentKey);
    stuAddress.HasKey<string>(s => s.AddressId);
       
    //2. 设置非空 (扩展:IsOptional 设置可空)
    stu.Property(p => p.stuName).IsRequired( );
    
    //3. 设置最大值(不能设置最小值)
    stu.Property(p => p.stuTxt1).HasMaxLength(10);
    
    //4. 修改列的名称、排序、类型
    stuAddress.Property(p => p.stuAddrssName2).HasColumnName("myAddress2").HasColumnOrder(1).HasColumnType("varchar");
    
    //5.修改表名
    stu.Map<Student>(c =>
    {
    c.ToTable("MyStudent");
    });
    
    //6.将一个实体映射成多张表,并分别给其命名
    //stuAddress.Map<StudentAddress>(c =>
    //{
    // c.Properties(p => new
    // {
    // p.AddressId,
    // p.AddressName
    // });
    // c.ToTable("MyStuAddress1");
    //}).Map<StudentAddress5>(c =>
    //{
    // c.Properties(p => new
    // {
    // p.stuAddressId,
    // p.stuAddrssName2
    // });
    // c.ToTable("MyStuAddress2");
    //});
    
    //三. 将Game实体的配置添加进来
    modelBuilder.Configurations.Add(new GameConfiguration());
    base.OnModelCreating(modelBuilder);
    }
    }
    示例

    (3)EF CodeFirst 数据库初始化策略和数据迁移

    ①数据库初始化策略

    四种策略:

    • CreateDatabaseIfNotExists:EF的默认策略,一旦model发生变化,抛异常,提示数据迁移
    • DropCreateDatabaseIfModelChanges:一旦model发生变化,删除数据库重新生成
    • DropCreateDatabaseAlways:数据库每次都重新生成
    • 自定义初始化(继承上面的三种策略中任何一种,然后追加自己的业务)

    也可以关闭Database.SetInitializer<dbContext6>(null);关闭后改变实体类,不会报错,不会丢失数据,但也无法映射改变数据库结构。

    public class MySchoolEntities : DbContext
    {
    public MySchoolEntities (): base("name=MySchool")
    {
    //在这里可以改变生成数据库的初始化策略
    //1. CreateDatabaseIfNotExists (EF的默认策略,数据库不存在,生成数据库;一旦model发生变化,抛异常,提示走数据迁移)
    //Database.SetInitializer<MySchoolEntities>(new CreateDatabaseIfNotExists<MySchoolEntities >());
    
    //2. DropCreateDatabaseIfModelChanges (一旦model发生变化,删除数据库重新生成)
    //Database.SetInitializer<MySchoolEntities >(new DropCreateDatabaseIfModelChanges<MySchoolEntities >());
    
    //3.DropCreateDatabaseAlways (数据库每次都重新生成)
    //Database.SetInitializer<MySchoolEntities >(new DropCreateDatabaseAlways<MySchoolEntities >());
    
    //4. 自定义初始化(继承上面的三种策略中任何一种,然后追加自己的业务)
    //Database.SetInitializer<MySchoolEntities >(new MySpecialIntializer());
    
    //5. 禁用数据库策略(不会报错,不会丢失数据,但是改变不了数据库的结构了)
    //Database.SetInitializer<MySchoolEntities >(null);
    }
    
    public DbSet<Animal> Animal { get; set; }
    public DbSet<AnimalKind> AnimalKind { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    base.OnModelCreating(modelBuilder);
    }
    
    /// <summary>
    /// 自定义一个初始化策略,每次初始化时追加10条数据
    /// </summary>
    public class MySpecialIntializer :
    DropCreateDatabaseAlways<MySchoolEntities >
    {
    public override void InitializeDatabase(MySchoolEntities context)
    {
    base.InitializeDatabase(context);
    }
       
    //重写seed,追加初始数据
    protected override void Seed(MySchoolEntities context)
    {
    for (int i = 0; i < 10; i++)
    {
    context.Animal.Add(new Animal()
    {
    id = "animal" + i,
    animalName = "mru" + i,
    animalKind = "mruru" + i,
    });
    }
    context.SaveChanges();
    base.Seed(context);
    }
    }
    }
    策略

    数据迁移

    解决修改表结构,数据丢失的问题。两种方式:

    • 自动迁移(不安全)
    //(1)新建Configuration.cs类,在其构造函数中进行相关配置。
    internal sealed class Configuration :
    DbMigrationsConfiguration<MySchoolEntities >
    {
    public Configuration()
    {
    AutomaticMigrationsEnabled = true; //(2)启用自动迁移
    AutomaticMigrationDataLossAllowed = true; //(3)更改数据库中结构(增加、删除列、修改列、改变列的属性、增加、删除、修改表),需要显示开启。}}
    
    public class MySchoolEntities : DbContext
    {
    public MySchoolEntities (): base("name=MySchool")
    {
    //数据库迁移配置
    //数据库迁移的初始化方式
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<MySchoolEntities , Configuration>("MySchoolEntities"));
    }
    
    public DbSet<Animal> Animal { get; set; }
    public DbSet<AnimalKind> AnimalKind { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    base.OnModelCreating(modelBuilder);
    }
    }
    步骤
    • 手动迁移

      (1)通过“程序包管理器控制台”的enable-migrations命令启动数据迁移。该命令只需执行一次

        作用:在项目根目录下创建了一个Migrations文件夹,在Migrations文件夹下新建一个Configuration.cs文件。

      (2)执行添加“add-migration InitialCreate”命令

        作用:产生一个<timestamp>_InitialCreate.cs的文件,文件中的两个方法(Up和Down)用来完成数据的更改

      (3)执行更新“update-database”命令

        作用:完成数据库的更新

    • 迁移回退
      PM> update-database -TargetMigration:SchoolDB-v1

     

    1.1 ORM性能问题

    • 复杂的对象管理机制:执行数据库会全程跟踪,降低性能
    • 高度封装执行机制:编写的表达式都要解析成SQL语句。
    • 低效的SQL语句:映射机制转将对象操作换为SQL语句,效率低。

    1.2 EF的状态管理

    在程序中实现数据的增、删、改操作,EF会监控这些状态的变化,在执行SaveChange()方法时,会根据对象状态的变化执行相应的操作。

    using (MySchoolContext db = new MySchoolContext())
    
    {
    
    Grade grade = new Grade() { GradeName = "Y3" };
    
    //输出当前对象状态
    
    Console.WriteLine(db.Entry(grade).State);  //通过Entry()方法获取模型状态
    
       
    
    db.Grade.Add(grade);
    
    Console.WriteLine(db.Entry(grade).State);
    
       
    
    db.SaveChanges();
    
    Console.WriteLine(db.Entry(grade).State);
    
    }
    代码

    方法或属性

    说明

    CurrentValues

    获取由此对象表示的跟踪实体的当前属性值

    OriginalValues

    获取由此对象表示的跟踪实体的原始属性值

    State

    获取或设置实体的状态

    Reload()

    从数据库重新加载对象的值

    其中,State属性是一个EntityState枚举类型,其取值如下:

    执行过程:  --Detached 游离、Added 添加、Unchanged 未改变、Modified 已修改、Deleted 已删除、Detached 游离

    Detached 表示对象存在,但没有被跟踪
    Unchanged 表示对象尚未经过修改
    Added 表示对象为新对象,并且已添加到对象上下文
    Deleted 对象已从对象上下文中删除
    Modified 表示对象的一个标量属性已更改

    1.3查询不进行跟踪

    • AsNoTracking()方法

    using (MySchoolContext db = new MySchoolContext())

    {

    var result = db.Student.AsNoTracking().FirstOrDefault();

    Console.WriteLine(db.Entry(result).State);

    }

    • 设置Configuration.AutoDetectChangesEnabled 属性为false

    using (MySchoolContext db = new MySchoolContext())

    {

    //禁用自动跟踪变化

    db.Configuration.AutoDetectChangesEnabled = false;

    for (int i = 0; i < 5000; i++)

    {

    var stu = new Student() { StudentName = "alex",

    GradeId = 1, Age = 20 };

    db.Student.Add(stu);

    }

    db.SaveChanges();

    }

    在使用EF修改或删除数据时,必须先查询对象,然后再对其进行修改或删除。然而现实开发中很多情况都是通过主键删除一条数据。我们可以通过实体的状态特性来进行优化。

    using (MySchool1Entities entities = new MySchool1Entities())

    {

    //创建替身对象

    var stu = new Student { StudentNo = "10001" };

    //给实体附加到上下文中

    entities.Student.Attach(stu);

    //删除

    entities.Student.Remove(stu);

    entities.SaveChanges();

    }

    代码中的Attach()方法可以将EntityState.Unchangee状态的对象附加到上下文中。

    2.加载

    • 延迟加载

      每次调用时再去查询,两个条件:①Poco类是Public且不能为Sealed。 ②导航属性需要标记为Vritual。

    • 贪懒加载

      一次性将数据读取出来,从缓存中读取,不用在查询数据库,两个条件:先关闭延迟加载。 ②查询主表的同时通过Include把从表数据也查询出来。

    • 显示加载

      --步骤:①单个实体用:Reference  ②集合用:Collection  ③最后需要Load一下

    注意:默认用延迟,多次读数据库用贪婪。

    //延迟加载
    using (dbContext1 db = new dbContext1())
    {
    
    Console.WriteLine("---------------- 01-延迟加载 ---------------");
    
    
    //EF默认就是延迟加载,默认下面的语句就是true,关闭则false
    
    db.Configuration.LazyLoadingEnabled = true;
    
    
    var list = db.Student.ToList(); //此处加载的数据,没有对从表进行任何查询操作
    
    
    foreach (var stu in list)
    {
    Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId, stu.studentName);
    
    //下面调用导航属性(一对一的关系) 每次调用时,都要去查询数据库
    var stuAddress = stu.StudentAddress;
    Console.WriteLine("地址编号:{0},地址名称:{1}",
    stuAddress.studentAddressId, stu.studentName);
    
    }
    }
    
    
    //贪懒加载
    using (dbContext1 db = new dbContext1())
    {
    Console.WriteLine("------------------- 03-立即加载 ------------------");
       
    //1.关闭延迟加载
    
    db.Configuration.LazyLoadingEnabled = false;
    
    //2. 获取主表数据的同时,通过Include将从表中的数据也全部加载出来
    var list = db.Student.Include("StudentAddress").ToList();
    foreach (var stu in list)
    {
    Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId,
    stu.studentName);
    //这里获取从表中的数据,均是从缓存中获取,无需查询数据库
    var stuAddress = stu.StudentAddress;
    Console.WriteLine("地址编号:{0},地址名称:{1}",
    stuAddress.studentAddressId, stu.studentName);
    }
    }
    
    
    
    //显示加载
    
    using (dbContext1 db = new dbContext1())
    {
    Console.WriteLine("----------------- 04-显式加载 ------------------");
    
    //1.关闭延迟加载
    db.Configuration.LazyLoadingEnabled = false;
    
    //2.此处加载的数据,不含从表中的数据
    var list = db.Student.ToList();
    foreach (var stu in list)
    {
    Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId,
    stu.studentName);
    
    
    //3.下面的这句话,可以开启重新查询一次数据库
    //3.1 单个属性的情况用Refercence
    db.Entry<Student>(stu).Reference(c => c.StudentAddress).Load();
    
    //3.2 集合的情况用Collection
    //db.Entry<Student>(stu).Collection(c => c.StudentAddress).Load();
    
    //下面调用导航属性(一对一的关系) 每次调用时,都要去查询数据库
    var stuAddress = stu.StudentAddress;
    Console.WriteLine("地址编号:{0},地址名称:{1}",
    stuAddress.studentAddressId, stu.studentName);
    }
    }
    代码

    3.缓存

    • EF的dbset<T>的Local属性提供缓存
    • DbSet<T>提供了 Find()方法,用于通过主键查找实体速度比First方法快的多,并且如果相应的实体已经被DbContext缓存,EF会在缓存中直接返回对应的实体,不执行数据库访问。

    4.事务

    •  SaveChanges
    • DbContextTransaction
    • TransactionScope
    using (DbContext db = new CodeFirstModel())
    {
    //增加
    TestInfor t1 = new TestInfor()
    {
    id = Guid.NewGuid().ToString("N"),
    txt1 = "txt1",
    txt2 = "txt2"
    };
    
    db.Set<TestInfor>().Add(t1);
    
    //删除
    TestInfor t2 = db.Set<TestInfor>().Where(u => u.id == "1").FirstOrDefault();
    if (t2 != null)
    {
    db.Set<TestInfor>().Remove(t2);
    }
    
    //修改
    
    TestInfor t3 = db.Set<TestInfor>().Where(u => u.id == "3").FirstOrDefault();
    
    t3.txt2 = "我是李马茹23";
    
       
    
    //SaveChanges事务提交
    
    int n = db.SaveChanges();  //一次性统一或回滚
    
    Console.WriteLine("数据作用条数:" + n);
    
    }
    SaveChanges
    using (DbContext db = new CodeFirstModel())
    
    {
    
    DbContextTransaction trans = null;
    
    try
    
    {
    
    //开启事务
    
    trans = db.Database.BeginTransaction();  //多个SaveChanges
    
    //增加
    
    string sql1 = @"insert into TestInfor values(@id,@txt1,@txt2)";
    
    SqlParameter[] pars1 ={
    
    new SqlParameter("@id",Guid.NewGuid().ToString("N")),
    
    new SqlParameter("@txt1","txt11"),
    
    new SqlParameter("@txt2","txt22")
    
    };
    
    db.Database.ExecuteSqlCommand(sql1, pars1);
    
    //删除
    
    string sql2 = @"delete from TestInfor where id=@id";
    
    SqlParameter[] pars2 ={
    
    new SqlParameter("@id","22")
    
    };
    
    db.Database.ExecuteSqlCommand(sql2, pars2);
    
    //修改
    
    string sql3 = @"update TestInfor set txt1=@txt1 where id=@id";
    
    SqlParameter[] pars3 ={
    
    new SqlParameter("@id","3"),
    
    new SqlParameter("@txt1","二狗子")
    
    };
    
    db.Database.ExecuteSqlCommand(sql3, pars3);
    
       
    
    //提交事务
    
    trans.Commit();
    
    Console.WriteLine("事务成功了");
    
    }
    
    catch (Exception ex)
    
    {
    
    Console.WriteLine(ex.Message);
    
    trans.Rollback(); //回滚
    
       
    
    }
    
    finally
    
    {
    
    //也可以把该事务写到using块中,让其自己托管,就不需要手动释放了
    
    trans.Dispose();
    
    }
    
    }
    DBContextTransaction
    using (DbContext db = new CodeFirstModel())
    
    {
    
    //自动脱管,不需要手动释放 多数据库连接
    
    using (DbContextTransaction trans = db.Database.BeginTransaction())
    
    {
    
    try
    
    {
    
    TestInfor t1 = new TestInfor()
    
    {
    
    id = Guid.NewGuid().ToString("N"),
    
    txt1 = "111111111",
    
    txt2 = "222222222222"
    
    };
    
    db.Entry(t1).State = EntityState.Added;
    
    db.SaveChanges();
    
       
    
    TestInfor t2 = new TestInfor()
    
    {
    
    id = Guid.NewGuid().ToString("N") + "123",
    
    txt1 = "111111111",
    
    txt2 = "222222222222"
    
    };
    
    db.Entry(t2).State = EntityState.Added;
    
    db.SaveChanges();
    
       
    
    trans.Commit();
    
    }
    
    catch (Exception)
    
    {
    
    trans.Rollback();
    
    }
    
    }
    
    }
    TransactionScope

    5.从实体框架回归SQL

    EF在DbContext类的Database属性里提供了ExecuteSqlCommand()和SqlQuery()两个方法,用来直接访问数据库。

    • ExecuteSqlCommand()
    • SqlQuery()
    using (MySchool1Entities db = new MySchool1Entities())
    
    {
    
    //执行update语句
    
    string sql = "update grade set gradeName=@gradeName where
    
    gradeId=@gradeId";
    
    SqlParameter[] ps =
    
    {
    
    new SqlParameter("@gradeName","第二学年"),
    
    new SqlParameter("@gradeId",3)
    
    };
    
    int result=db.Database.ExecuteSqlCommand(sql, ps);  //返回影响行数
    
    if (result>0)
    
    {
    
    Console.WriteLine("数据更新完成!");
    
    }
    
    //执行查询语句
    
    sql = "select * from from student where studentNo=@stuNo";
    
    ps = new SqlParameter[] { new SqlParameter("@stuNo", "S1001234") };
    
    var stu = db.Database.SqlQuery<Student>(sql, ps);  //返回集合
    
    Console.WriteLine(stu.ToList()[0]);
    
    }
    代码

    封装EF的DAL层

      public class BaseDAL<T> where T:class
      2     {
      3         private DbContext db
      4         {
      5             get
      6             {
      7                 DbContext dbContext = CallContext.GetData("dbContext") as DbContext;
      8                 if (dbContext == null)
      9                 {
     10                     dbContext = new MySchoolContext();
     11                     CallContext.SetData("dbContext", dbContext);
     12                 }
     13                 return dbContext;
     14             }
     15         }
     16 
     17         /// <summary>
     18         /// 执行增加,删除,修改操作(或调用存储过程)
     19         /// </summary>
     20         /// <param name="sql"></param>
     21         /// <param name="pars"></param>
     22         /// <returns></returns>
     23         public int ExecuteSql(string sql, params SqlParameter[] pars)
     24         {
     25             return db.Database.ExecuteSqlCommand(sql, pars);
     26         }
     27 
     28         /// <summary>
     29         /// 执行查询操作
     30         /// </summary>
     31         /// <typeparam name="T"></typeparam>
     32         /// <param name="sql"></param>
     33         /// <param name="pars"></param>
     34         /// <returns></returns>
     35         public List<T> ExecuteQuery(string sql, params SqlParameter[] pars)
     36         {
     37             return db.Database.SqlQuery<T>(sql, pars).ToList();
     38         }
     39 
     40         /// <summary>
     41         /// 添加
     42         /// </summary>
     43         /// <param name="model"></param>
     44         /// <returns></returns>
     45         public int Add(T model)
     46         {
     47             db.Set<T>().Add(model);
     48             return db.SaveChanges();
     49         }
     50 
     51         /// <summary>
     52         /// 删除(适用于先查询后删除的单个实体)
     53         /// </summary>
     54         /// <param name="model">需要删除的实体</param>
     55         /// <returns></returns>
     56         public int Del(T model)
     57         {
     58             db.Set<T>().Attach(model);
     59             db.Set<T>().Remove(model);
     60             return db.SaveChanges();
     61         }
     62 
     63         /// <summary>
     64         /// 根据条件删除(支持批量删除)
     65         /// </summary>
     66         /// <param name="delWhere">传入Lambda表达式(生成表达式目录树)</param>
     67         /// <returns></returns>
     68         public int DelBy(Expression<Func<T, bool>> delWhere)
     69         {
     70             var listDels = db.Set<T>().Where(delWhere);
     71             foreach(var model in listDels)
     72             {
     73                 db.Set<T>().Attach(model);
     74                 db.Set<T>().Remove(model);
     75             }
     76             return db.SaveChanges();
     77         }
     78 
     79         /// <summary>
     80         /// 修改
     81         /// </summary>
     82         /// <param name="model">修改后的实体</param>
     83         /// <returns></returns>
     84         public int Modify(T model)
     85         {
     86             db.Entry(model).State = EntityState.Modified;
     87             return db.SaveChanges();
     88         }
     89 
     90         /// <summary>
     91         /// 批量修改
     92         /// </summary>
     93         /// <param name="model">要修改实体中 修改后的属性 </param>
     94         /// <param name="whereLambda">查询实体的条件</param>
     95         /// <param name="proNames">lambda的形式表示要修改的实体属性名</param>
     96         /// <returns></returns>
     97         public int ModifyBy(T model, Expression<Func<T, bool>> whereLambda, params string[] proNames)
     98         {
     99             List<T> listModifes = db.Set<T>().Where(whereLambda).ToList();
    100             Type t = typeof(T);
    101             List<PropertyInfo> proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
    102             Dictionary<string, PropertyInfo> dicPros = new Dictionary<string, PropertyInfo>();
    103             proInfos.ForEach(p =>
    104             {
    105                 if (proNames.Contains(p.Name))
    106                 {
    107                     dicPros.Add(p.Name, p);
    108                 }
    109             });
    110             foreach (string proName in proNames)
    111             {
    112                 if (dicPros.ContainsKey(proName))
    113                 {
    114                     PropertyInfo proInfo = dicPros[proName];
    115                     object newValue = proInfo.GetValue(model, null);
    116                     foreach (T m in listModifes)
    117                     {
    118                         proInfo.SetValue(m, newValue, null);
    119                     }
    120                 }
    121             }
    122             return db.SaveChanges();
    123         }
    124 
    125         /// <summary>
    126         /// 根据条件查询
    127         /// </summary>
    128         /// <param name="whereLambda">查询条件(lambda表达式的形式生成表达式目录树)</param>
    129         /// <returns></returns>
    130         public IQueryable<T> GetListBy(Expression<Func<T, bool>> whereLambda)
    131         {
    132             return db.Set<T>().Where(whereLambda);
    133         }
    134         /// <summary>
    135         /// 根据条件排序和查询
    136         /// </summary>
    137         /// <typeparam name="Tkey">排序字段类型</typeparam>
    138         /// <param name="whereLambda">查询条件</param>
    139         /// <param name="orderLambda">排序条件</param>
    140         /// <param name="isAsc">升序or降序</param>
    141         /// <returns></returns>
    142         public IQueryable<T> GetListBy<Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true)
    143         {
    144             if (isAsc)
    145             {
    146                 return db.Set<T>().Where(whereLambda).OrderBy(orderLambda);
    147             }
    148             else
    149             {
    150                 return db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda);
    151             }
    152         }
    153         /// <summary>
    154         /// 分页查询
    155         /// </summary>
    156         /// <typeparam name="Tkey">排序字段类型</typeparam>
    157         /// <param name="pageIndex">页码</param>
    158         /// <param name="pageSize">页容量</param>
    159         /// <param name="whereLambda">查询条件</param>
    160         /// <param name="orderLambda">排序条件</param>
    161         /// <param name="isAsc">升序or降序</param>
    162         /// <returns></returns>
    163         public IQueryable<T> GetPageList<Tkey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true)
    164         {
    165 
    166             IQueryable<T> list = null;
    167             if (isAsc)
    168             {
    169                 list = db.Set<T>().Where(whereLambda).OrderBy(orderLambda)
    170                .Skip((pageIndex - 1) * pageSize).Take(pageSize);
    171             }
    172             else
    173             {
    174                 list = db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda)
    175               .Skip((pageIndex - 1) * pageSize).Take(pageSize);
    176             }
    177             return list;
    178         }
    179         /// <summary>
    180         /// 分页查询输出总行数
    181         /// </summary>
    182         /// <typeparam name="Tkey">排序字段类型</typeparam>
    183         /// <param name="pageIndex">页码</param>
    184         /// <param name="pageSize">页容量</param>
    185         /// <param name="whereLambda">查询条件</param>
    186         /// <param name="orderLambda">排序条件</param>
    187         /// <param name="isAsc">升序or降序</param>
    188         /// <returns></returns>
    189         public IQueryable<T> GetPageList<Tkey>(int pageIndex, int pageSize, out int rowCount, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true)
    190         {
    191             IQueryable<T> list = null;
    192             rowCount = db.Set<T>().Where(whereLambda).Count();
    193             if (isAsc)
    194             {
    195                 list = db.Set<T>().Where(whereLambda).OrderBy(orderLambda)
    196                    .Skip((pageIndex - 1) * pageSize).Take(pageSize);
    197             }
    198             else
    199             {
    200                 list = db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda)
    201                  .Skip((pageIndex - 1) * pageSize).Take(pageSize);
    202             }
    203             return list;
    204         }
    205 
    206 
    207     }
    View Code
    • DbContextTransaction
  • 相关阅读:
    .NET下的并行开发
    .NET下单文件的上传处理
    .NET下dropdownlist的基本操作
    [Python3网络爬虫开发实战] 3.1.1-发送请求
    [Python3网络爬虫开发实战] 3.1.2-处理异常
    [Python3网络爬虫开发实战] 3.1-使用urllib
    [Python3网络爬虫开发实战] 2.4-会话和Cookies
    [Python3网络爬虫开发实战] 2.5-代理的基本原理
    [Python3网络爬虫开发实战] 2.3-爬虫的基本原理
    [Python3网络爬虫开发实战] 2.2-网页基础
  • 原文地址:https://www.cnblogs.com/shishixiang/p/14024465.html
Copyright © 2020-2023  润新知