一.Entity Framework的入门 我这里采用的方式是数据库自己建立 然后模型类自己建立 数据库上下文类自己建立的方式 目的在于弄懂原理 其他的数据库优先等方式这里就不写了 教程有很多。
首先创建控制台应用程序,接下来选择工具 NuGet包管理器,程序包管理控制台,默认项目选择自己要使用的项目,输入命令Install-Package EntityFramework 安装EntityFramework 。
a.安装成功后,在appconfig中添加数据库连接字符串:
<connectionStrings>
<add name="connStr" connectionString="Data Source=.;Initial Catalog=test2;User ID=sa;Password=123456" providerName="System.Data.SqlClient" />
</connectionStrings>
b.添加模型类Person:
[Table("T_Persons")]
public class Person
{
public long Id { get; set; }
public string Name { get; set; }
public DateTime CreateDatetime { get; set; }
}
[Table("T_Persons")]用于告诉程序当前的类Person映射到数据库中的T_Persons表。因为现实中很有可能我们的数据库中的表名不一定和实体类名一致。
c.添加数据库上下文类
public class MyDbContext : DbContext
{
public MyDbContext() : base("name=connStr")
{
}
public DbSet<Person> Persons { get; set; }
}
好了 到这里所以需要的准备工作已经完成 开始测试
class Program
{
static void Main(string[] args)
{
try
{
MyDbContext db = new MyDbContext();
Person p = new Person
{
Name = "五二狗",
CreateDatetime = DateTime.Now
};
db.Persons.Add(p);
db.SaveChanges();
Console.WriteLine("添加成功");
}
catch(Exception ex)
{
Console.WriteLine($"添加失败,{ex.Message}");
}
Console.ReadKey();
}
}
测试已经添加成功 ef测试ok。
二.FluentApi的学习以及使用
a.下载entityframework包并且安装
b.配置数据库连接字符串
c.新建模型类Person 这个模型类区别于上面的用法是这个模型类是一个纯净的模型类 没有其他的特性修饰
public class Person
{
public long Id { get; set; }
public string Name { get; set; }
public DateTime CreateDatetime { get; set; }
}
d.新建文件夹EntityConfig(其他文件夹名字也可 不建也可 建文件夹只是为了方便统一管理) 文件夹下添加类PersonConfig继承EntityTypeConfiguration<Person>
public class PersonConfig:EntityTypeConfiguration<Person>
{
public PersonConfig()
{
this.ToTable("T_Persons");
}
}
其实这一段代码等同于上面的[Table("T_Persons")]特性
e.新建数据库上下文类
public class MyContext : DbContext
{
public MyContext():base("name=connStr")
{
}
public DbSet<Person> Persons { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());
}
}
ok 其他用法完全一致测试如下:
class Program
{
static void Main(string[] args)
{
MyContext db = new MyContext();
Person p = new Person { Name = "张三", CreateDatetime = DateTime.Now };
db.Persons.Add(p);
db.SaveChanges();
Console.WriteLine("添加成功");
}
}
三.Entity Framework 的增删改查
try
{
TestDbContext ctx = new TestDbContext();
#region 添加
/*
Person p1 = new Person { Name = "孔夫子", CreateDatetime = DateTime.Now };
Console.WriteLine($"添加前Id是{p1.Id}");
ctx.Persons.Add(p1);
ctx.SaveChanges();
Console.WriteLine("添加成功");
Console.WriteLine($"添加成功后Id是{p1.Id}");
*/
#endregion
#region 查询
/*
var list = ctx.Persons.Where(x => x.Name == "孔夫子");
foreach (var item in list)
{
Console.WriteLine(item);
}
var item = ctx.Persons.FirstOrDefault(x => x.Name == "孔夫子");
Console.WriteLine(item);
var item = ctx.Persons.SingleOrDefault(x => x.Name == "孔夫子");
Console.WriteLine(item);
*/
#endregion
#region 删除
/*
var item = (from p in ctx.Persons
where p.Name == "孔夫子"
select p).SingleOrDefault();
var item1 = ctx.Persons.Where(x => x.Name == "孔夫子").SingleOrDefault();
var item2 = ctx.Persons.SingleOrDefault(x => x.Name == "孔夫子");
if(item==null)
{
Console.WriteLine("已被删除");
}
else
{
ctx.Persons.Remove(item);
ctx.SaveChanges();
Console.WriteLine("删除成功");
}
*/
#endregion
#region 修改
/*
var item = ctx.Persons.FirstOrDefault(x => x.Name == "五二狗");
if (item == null)
{
Console.WriteLine("查无此人");
}
else
{
item.Name = "六二狗";
}
ctx.SaveChanges();
Console.WriteLine(item);
*/
#endregion
}
catch (Exception ex)
{
Console.WriteLine("出现错误 "+ex.Message);
}
Console.ReadKey();
四.Entity Framework 原理和sql监控
如何查看我们最终到数据库中运行的sql语句呢?
#region EF原理
a.查看执行的sql
ctx.Database.Log = sql => { Console.WriteLine("*******Log******"+sql); };
var perons = ctx.Persons.Where(x => x.Name == "六二狗").SingleOrDefault();
Console.WriteLine(perons.Name);
Console.WriteLine("结束");
#endregion
添加这样一段代码就可以 其中ctx.Database.Log属性是Databse类下面的一个属性,它的类型是public Action<string> Log { get; set; }。即一个参数是string类型,没有返回类型的委托
因此我们让Log属性指向委托sql => { Console.WriteLine("*******Log******"+sql); };在程序运行过程中就可以看见具体的执行内容如下图
其中关于dbo.__MigrationHistory的可以去掉 目前暂时用不到
在数据库上下文类的构造函数中添加如下代码:
public TestDbContext() : base("name=connStr")
{
Database.SetInitializer<TestDbContext>(null);
}
再次测试:
控制台很干净了 不必要的代码都省去了。
b.ToList()的立即执行理解
看下面的一段代码
#region EF原理
ctx.Database.Log = sql => { Console.WriteLine("*******Log******"+sql); };
var perons = ctx.Persons.Where(x => x.Name.Contains("二")).ToList();
IEnumerable<Person> p = perons.Where(x => x.Name.StartsWith("章"));
//Console.WriteLine(perons.Name);
List<Person> testp = p.ToList();
Console.WriteLine("结束");
#endregion
对应的执行sql
sql只执行了对于二的查询 而章并没有参与到数据库查询中。这是因为tolist()是立即执行的。在使用了tolist()之后 ,程序已经将所有的数据加载到了内存中
此时对章的选择已经不是针对于数据库了 而是内存中的一系列数据
同理 加入第一次查询的结果保存到IEnumerable类型中 也会存在同样的问题 IEnumerable也会将结果加载到内存中
#region EF原理
ctx.Database.Log = sql => { Console.WriteLine("*******Log******"+sql); };
IEnumerable<Person> perons = ctx.Persons.Where(x => x.Name.Contains("二"));
IEnumerable<Person> p = perons.Where(x => x.Name.StartsWith("章"));
//Console.WriteLine(perons.Name);
List<Person> testp = p.ToList();
Console.WriteLine("结束");
#endregion
那么换一种方式 使用IQueryable
#region EF原理
ctx.Database.Log = sql => { Console.WriteLine("*******Log******"+sql); };
IQueryable<Person> perons = ctx.Persons.Where(x => x.Name.Contains("二"));
IQueryable<Person> p = perons.Where(x => x.Name.StartsWith("章"));
//Console.WriteLine(perons.Name);
List<Person> testp = p.ToList();
Console.WriteLine("结束");
#endregion
可以看到 在数据库查询条件同时执行了 这样效率也当然高于先查一部分数据 然后加载到内存中 之后在内存中在对这一系列数据进行操作
五.Entity Framework 直接执行sql
#region EF执行sql语句
/*
//ctx.Database.ExecuteSqlCommand("insert into T_persons (name,createdatetime) values ('吴晓龙',GetDate())");
//Console.WriteLine("添加成功");
ctx.Database.Log = sql => { Console.WriteLine("*******Log******" + sql); };
string name = Console.ReadLine();
//ctx.Database.ExecuteSqlCommand($"insert into T_persons (name,createdatetime) values ('{name}',GetDate())");
ctx.Database.ExecuteSqlCommand("insert into T_persons (name,createdatetime) values ({0},GetDate())",name);
Console.WriteLine("添加成功");
*/
#endregion