一、EF 开发方法
存在三种方式来使用 EF:数据库优先,模型优先和代码优先。
Database First(数据库优先):Existing Database -> Generated Data Model(.edmx)
Model First(模型优先):Data Model(.edmx) -> Generated Databse
Code First(代码优先):Data Model(classes) -> Generated Database
或
Existing Database -> Generated Data Model(classes)
数据库优先:
如果你已经创建了数据库,EF可以自动生成创建数据模型,包含关联到数据库中表和字段的类和属性。关于数据库结构的信息(存储架构)
数据模型(概念模型)、它们之间的映射被存储在扩展名为.edmx的XML文件中。Visual Studio提供了EF设计器,这是一个图形化的设计器,
可以用来显示和编辑.edmx文件。
模型优先
如果你还没有数据库,你可以在Visual Studio中使用EF的设计器通过创建模型来开始。当模型创建之后,设计器可以生成DDL语句来创建
相应的数据库。这个方法也使用.edmx文件来存储模型以及映射信息。
代码优先
不管你是否已经有数据库,你仍然可以编写自己的类和数据关联到数据表和字段,使用EF而不需要.edmx文件。所有有时候这种方法又被称
为Code Onle。当然典型的名称为Code First。在数据库的存储架构到概念模型之间的映射通过约定以及特定的映射API完成。如果你还没
有数据库,EF可以自动为你创建它,在模型改变的时候,先删除掉然后重新创建,这个教程使用代码优先的方式进行开发。
=========================================================================================================================
=========================================================================================================================
一、实体数据模型,简称EDM,由三个概念组成。
1、概念架构定义语言文件(.csdl) -- 定义概念模型。
2、存储架构定义语言文件(.ssdl) -- 定义存储模型(又称逻辑模型)
3、映射规范语言文件(.msl) -- 定义存储模型与概念模型之间的映射。
这三者合在一起就是EDM模式。EDM模式在项目中的表现形式就是扩展名为.edmx的文件。
4、EF中4个重要类
ObjectContext、ObjectQuery、ObjectStateEntry、ObjectStateManager
位于System.Data.Objects命名空间下
5、ObjectContext:封装 .NET Framework 和数据库之间的连接。此类用作“创建”、“读取”、“更新”和“删除”操作的网关。
ObjectContext类为主类,用于与作为对象(这些对象为 EDM 中定义的实体类型的实例)的数据进行交互。
ObjectContext类的属性:
到数据库的连接,以 EntityConnection 对象的形式封装。
描述该模型的元数据,以 MetadataWorkspace 对象的形式封装。
用于管理缓存中持久保存的对象的 ObjectStateManager 对象。
6、ObjectContext类的成员方法以说明如下所示:
AcceptAllChanges():接受所有对该实体对象的更改
AddObject(string,object):将实体对象添加到制定的实体容器中
ApplyPropertyChanges(string,object):将以指派的实体对象属性的更改应用到容器中对应的原对象。(4.0中已过期)
Attach(System.Data.Objects.DataClasses.IEntityWithKey entity):将带主键的实体对象附加到默认的容器中
Attach(string,object):将实体对象附加到指定的实体容器中
CreateEntityKey(string,object):给指定的实体对象创建实体主键或如果已存在实体主键,则直接返回该实体的主键
CreateQuery<T>(string,params ObjectParameter[]):从给定的查询字符串创建ObjectQuery对象。
DeleteObject(object):删除指定的实体对象
Detach(object):移除指定的实体对象
ExecuteFunction<TElement>(string,params ObjectParameter[]):对默认容器执行给定的函数。
GetObjectByKey(System.Data.EntityKey key):通过主键KEY从 ObjectStateManager 中检索对象(如果存在);否则从存储区中检索。
Refresh(System.Data.Objects.RefreshMode refreshMode, object entity):按指定持久更新模式,使用指定实体的存储区数据更新
ObjectStateManager。。
Refresh(System.Data.Objects.RefreshMode refreshMode, System.Collections.IEnumerable collection):按指定持久处理模式,使用
指定实体集的存储区数据更新ObjectStateManager。
SaveChanges(bool):将所有更新持久保存到存储区中。参数是客户端事务支持所需的参数。参数为true则在更新后自动将更改应用到
ObjectStateManager中的实体。如果为false,则在更新后还需要调用AcceptAllChanges()以便更新ObjectStateManager中的
实体。
SaveChanges():将所有更新持久保存到存储区中
TryGetObjectByKey(System.Data.EntityKey,out object):尝试从指定实体主键返回该实体。
ApplyCurrentValues<TEntity>将标量值从提供的对象复制到ObjectContext中具有相同键的对象中,可以替代ApplyPropertyChanges
ApplyOriginalValues<TEntity>将标量值从提供的对象复制到ObjectContext中具有相同键的对象的原始值集中。
ExcuteFunction<TElememt>(string,params ObjectParameter[])对默认容器执行给定的函数
7、ObjectQuery是对Entity Data Model(EDM)的查询的基类。
8、ObjectStateEntry维护实体实例或关系实例的状态(已添加、已删除、已分离、已修改或未更改)、键值和原始值。还管理已修改属性的
列表。其包含一下方法:
属性:
CurrentValues:获取与此ObjectStateEntry关联的对象或关系的当前属性值。
OriginalValues:获取与此ObjectStateEntry关联的对象或关联的原始值得只读版本。若要获取课更新的原始值,请使用
GetUpdatableOriginalValues。
Entity:获取与此ObjectStateEntry关联的对象或关系的当前属性值
EntityKey
EntitySet
ObjectStateManager
State
方法:
AcceptChanges:接受当前值作为原始值,并将实体标记为 Unchanged()。
ApplyCurrentValues:设置项的当前值,使其与所提供对象的属性值项匹配。
ApplyOriginalValues:设置条目的原始值,使其与所提供对象的属性值项匹配。
ChangeState:将该项的状态更改为指定的EntityState值。
Delete:将实体标记为 Deleted()。如果实体处于 Added()()() 状态,它将为 Detached()。
GetModifiedProperties:返回标记为 Modified()的属性名称。
GetUpdatableOriginalValues:获取与此ObjectStateEntry关联的对象的原始值得可更新版本。
SetModified:将状态设置为 Modified()。
SetModifiedProperty:将指定的属性标记为 Modified()。
9、ObjectStateManager用于维护对象映射、对象状态/标识管理以及实体实例或关系实例的持久性。
TryGetObjectStateEntry:尝试返回特定对象或关系项的ObjectStateEntry对象。
GetObjectStateEntries:获取给定EntityState的ObjectStateEntry集合。
GetObjectStateEntry:获取给定的 EntityKey 对应的 ObjectStateEntry
二、LINQ TO Entites
1、自动属性
简化我们在.net中手写一堆私有成员+属性的编程方式,只需如下方式声明一个属性,编译器会自动生成所需的成员变量。
public class Customer
{
public int Id{get;set;}
public string Name{get;set;}
}
2、隐式类型(P34)
在c#中用var声明一个对象,编译器会自动根据其赋值语句推断这个局部变量的类型。赋值后,这个变量的类型也就确定而不可再更改。
LINQ中应用,var主要用途是表示一个LINQ查询的结果。
3、对象、集合初始化器(对象始化器与集合初始化器)
基本用法(对象初始化):
User user = new User{Id=1,Name="aaa",Age=22};
基本用法(集合初始化):
List<int> num = new List<int>{0,1,2,3,4,5,6,7,8,9};
结合对象初始化器,如下简洁的代码:
List<User> user = new List<User>{
new User{Id=1,Name="a",Age=22},
new User{Id=2,Name="b",Age=25},
};
4、匿名类(P36)
可以使用new{object initializer}或new[]{object,...}来初始化一个匿名类或不确定类型的数组。匿名类的对象需要使用var关键字声明
示例:var p1 = new {Id=1,Name="aa",Age=22};
5、扩展方法
public static class Extentsions
{
public static bool IsValidEmailAddress(this string s)
{
Regex regex = new Regex(@"^[\w-\.]+@([\w-\.]+[\w-]{2,4}$)";
return regex.IsMatch(s);
}
}
如上所示,扩展方法为一个静态方法,声明于一个静态类,其参数前加上一个this关键字,参数的类型表示这个扩展方法要对这个类型进
行扩展。如上代码表示其要对字符串类型进行扩展。在应用上扩展方法被作为其扩展的类型的静态方法来调用。如下
if(emial.IsValidEmailAddress())
{
Response.Write("这是一个正确的邮件地址")
}
6、Lambda表达式
var inString = list.FindAll(delegate(string s)
{
return s.Indexof("agg")>=0;
});
使用Lambda表达式代码将更自然易懂。
var inString = list.FindAll(s => s.Indexof("agg")>=0);
可以看出,Lamabda表达式格式为:(参数列表)=>表达式或语句块
7、几种技术在LINQ中的应用
var processes = Process.GetProcesses()
.Where(process => process.WorkingSet64 > 20*1024*1024)
.OrderByDescending(process => process.WorkingSet64)
.Select(process => new {process.Id,Name=process.ProcessName});
另一种表达
from [type] id in source
[join [type] id in source on expr equals expr [into id] ]
{ from [type] id in source | let id = expr | where condition }
[orderby ordering,...]
select expr | group expr by key
[into id query]
8、关键字
Select-选择需要返回的字段
Where-筛选
OrderBy-正序排序
OrderByDescending-倒序排序
ThenBy-在OrderBy或OrderByDescending的基础上在正序排序
ThenByDescending-在OrderBy或OrderByDescending的基础上再倒序排序
GroupBy-分组
Join-连接
GroupJoin-连接后分组
例子
using(var ctx new NorthwindEntities())
{
//select对应的linq方法
var p1 = ctx.Products.Select(p=>new{ProductName = "产品名称:"+p.ProductName});
p1.ToList();
//select对应的查询语句
var p2 = from p in ctx.Produces select new{ProductName="产品名称:"+p.ProductName};
//OrderBy对应的Linq方法
var p1=ctx.Products.OrderBy(p=>p.UnitPrice);
//OrderBy对应的查询语法
var p2=from p in ctx.Products orderby p.UnitPrice select p;
p2.ToList();
//OrderByDescending对应的Linq方法
var p1=ctx.Products.OrderByDescending(p=>p.UnitPrice);
//OrderByDescending对应的查询语法
var p2=from p in ctx.Products orderby p.UnitPrice descending select p;
p2.ToList();
}
例子
using(var ctx new NorthwindEntities())
{
//ThenBy对应的linq方法
var p1 = ctx.Products.OrderBy(p=>p.UnitPrice).ThenBy(p=>p.ProductID);
p1.ToList();
//ThenBy对应的查询语句
var p2 = from p in ctx.Produces orderby p.UnitPrice ascending,p.ProductID ascending select p;
//ThenByDescending对应的Linq方法
var p1=ctx.Products.OrderBy(p=>p.UnitPrice).ThenByDescending(p=>p.ProductID);
//ThenByDescending对应的查询语法
var p2=from p in ctx.Products orderby p.UnitPrice ascending,p.ProductID descending select p;
p2.ToList();
//GroupBy对应的Linq方法
var p1=ctx.Products.GroupBy(p=>p.Suppliners.SupplierID).select(g=>new{Group = g.Key,Member=g});
//GroupBy对应的查询语法
var p2=from p in ctx.Products group p by p.Suppliners.SupplierID into g select new{Group = g.Key,Member=g};
}
例子
using(var ctx = new NorthwindEntities())
{
//Join对应的Linq方法
var p1=ctx.Products.Join(
ctx.Categories,
p=>p.Categories.CategoryID,
c=>c.CategoryID,
(p,c)=>new{c.CategoryName,p.ProductName}
);
p1.ToList();
//Join对应的查询语法
var p2=from p in ctx.Products
join c in ctx.Categories
on p.Categories.CategoryID equals c.CategoryID
select new{c.CategoryName,p.ProductName};
p2.ToList();
}
例子
using(var ctx = new NorthwindEntities())
{
//GroupJoin对应的Linq方法
var p1=ctx.Categories.GroupJoin(
ctx.Products,
c=>c.CategoryID,
p=>p.Categories.CategoryID,
(p,g)=>new{p.CategoryName,ProductCount = g.Count() });
p1.ToList();
//GroupJoin对应的查询语法
var p2=from c in ctx.Categories
join p in ctx.Products
on c.CategoryID equals p.Categories.CategoryID into g
select new{CategoryName = c.CategoryName,ProductCount = g.Count() };
p2.ToList();
}
关键字
First-返回集合中的第一个成员;不延迟
FirstOrDefault-返回集合中的第一个成员(找不到则返回null);不延迟
All-是否集合中所有成员都满足某一条件;不延迟
Any-集合中是否有成员满足某一条件;不延迟
Average-取平均值;不延迟
Sum-求和;不延迟
Max-取最大值;不延迟
Min-取最小值;不延迟
Count-取指定集合的成员数,返回值类型int;不延迟
LongCount-取指定集合的成员数,返回值类型long;不延迟
Take-获取集合的前N个成员;延迟
Skip-跳过集合的前N个成员;延迟
Distinct-过滤集合相同项,去除重复值;延迟
Union-连接不通集合,自动过滤相同项;延迟
UnionAll-连接不通集合,不会自动过滤相同项;延迟
Concat-连接不通集合,不会自动过滤相同项;延迟
Insersect-获取不通集合的相同项(交集);延迟
Except-从某集合中删除其与另一个集合中相同的项;延迟
例子
using(var ctx = new NorthwindEntities())
{
IQueryable<Products> skip = ctx.Products.OrderBy(p=>p.UnitPrice).Skip(3);
skip.ToList();
ObjectQuery<Products> distinct = ctx.Products.Distinct();
ObjectQuery<Products> union = ctx.Products.Union(ctx.Products)
ObjectQuery<Products> unionAll = ctx.Products.UnionAll(ctx.Products);
ObjectQuery<Products> concat = ctx.Products.Concat(ctx.Products)
}
例子
using(var ctx = new NorthwindEntities())
{
Products first = ctx.Products.First(p=>p.ProductID > 3);
Products firstOrDefault = ctx.Products.FirstOrDefault(p=>p.ProductID > 100);
bool all = ctx.Products.All(p=>p.ProductID > 3);
bool any = ctx.Products.Any(p=>p.ProductID > 3);
decimal?average = ctx.Products.Average(p=>p.UnitPrice);
decimal?sum = ctx.Products.Sum(p=>p.UnitPrice);
decimal?max = ctx.Products.Max(p=>p.UnitPrice);
decimal?min = ctx.Products.Min(p=>p.UnitPrice);
int count = ctx.Products.Count(p=>p.ProductID > 3);
long longCount = ctx.Products.LongCount(p=>p.ProductID > 3);
IQueryable<Products> take = ctx.Products.Take(3);
take.ToList();
}
Queryable
提供一组用于查询实现IQueryable<T>的数据结构的static方法。
例子
using(var ctx = new NorthwindEntities())
{
ObjectQuery<Products> intersect = ctx.Products.Intersect(ctx.Products)
intersect.ToList();
ObjectQuery<Products> except = ctx.Products.Except(ctx.Products);
except.ToList();
}
二、Entity Sql(P53)
EF除了提供LINQ查询方式,还提供了Entity SQL Language
Entity Framework 4中的Code-First, Model-First和Database-First模式