深入理解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("学号\t姓名");
foreach (var stu in query)
{Console.WriteLine("{0}\t{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
posted @ 2020-11-23 14:56  未来尚可期  阅读(140)  评论(0编辑  收藏  举报