对象服务Object Services
在EntityClient provider上层,entityframework为了操作对象提供了另一套的抽象的集合。这一层通常被认为就是ORM,它在一个数据模型中完成CLR实例类型的定义并且允许开发人员使用Linq或ESQL查询那些对象。当你比较目前市场上使用的ORM框架,这层恰恰也是Entity Framework 最初吸引开发者关注的亮点所在。从图1可以看到对象服务层的功能是在应用程序中使用Linq或Esql,通过查询表达式到下面的EntityClient然后返回一个IEnumerable<T>。
然而,你可以看到(Object Services Layer)对象服务层最核心的是ObjectContext(应用程序和底层数据存储之间活动的session). ObjectContext对于开发人员而言主要的功能是查询,添加,删除实体实例和保存新状态到数据库。在图7中展示了如何创建和使用ObjectContext去查询,并且SaveChanges 一个实体(使用ESQL作为查询语言)Figure 7 Using ObjectContext
Code
1
using (ObjectContext context = new ObjectContext("name=travelEntities"))
2![](http://img.e-com-net.com/image/product/93a7f0399a9049a3b82d13dcc4073372.gif)
3![](http://img.e-com-net.com/image/product/8bf85857a9e14d23a651e7c8ef856bcc.gif)
{
4![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
5
//--- create a query for customers
6![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
7
ObjectQuery<Person> personQuery = context.CreateQuery<Person>(
8![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
9
@"select value c from travelEntitiesGeneral.People
10![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
11
as c where c.PersonID == 1");
12![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
13
//--- by enumerating the query will be implicitly executed
14![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
15
//--- against the store and you can now work with an
16![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
17
//--- IEnumerable<Customer>
18![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
19
foreach (Person c in personQuery)
20![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
21![](http://img.e-com-net.com/image/product/437570a32a8e47669b1b8f34e2a85bac.gif)
{
22![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
23
//--- dereference anything you like from Customer
24![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
25
Console.WriteLine(c.PersonID + ": " + c.Name);
26![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
27
c.Name = "New Name";
28![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
29
}
30![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
31
try
32![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
33![](http://img.e-com-net.com/image/product/437570a32a8e47669b1b8f34e2a85bac.gif)
{
34![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
35
context.SaveChanges();
36![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
37
}
38![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
39
catch (OptimisticConcurrencyException opt)
40![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
41![](http://img.e-com-net.com/image/product/437570a32a8e47669b1b8f34e2a85bac.gif)
{
42![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
43
// catching this exception allows you to
44![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
45
// refresh travelEntities with either store/client wins
46![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
47
// project the travelEntities into this failed travelEntities.
48![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
49
var failedEntities = from e3 in opt.StateEntries
50![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
51![](http://img.e-com-net.com/image/product/437570a32a8e47669b1b8f34e2a85bac.gif)
select new
{ e3.Entity };
52![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
53
54![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
55
// Note: in future you should be able to just pass
56![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
57
// the opt.StateEntities
58![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
59
// in to refresh.
60![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
61
context.Refresh(RefreshMode.ClientWins, failedEntities.ToList());
62![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
63
context.SaveChanges();
64![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
65
}
66![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
67
}
68![](http://img.e-com-net.com/image/product/93a7f0399a9049a3b82d13dcc4073372.gif)
69
跟踪内存中的对象的变化过程和保存那些变化到数据库的过程对于开发人员而言只需要简单地使用对象服务就可完成,Object Services通过对象状态管理器(ObjectStateManager)不仅能够跟踪当前内存中的对象状态还能跟踪从数据库取出时的原始状态。跟踪对象状态变化让保存对象到数据库变得更容易借助ObjectContext的SaveChanges方法。
基于上述那些,我只是阐述了一些基本的内容关于ObjectContext。例子中演示了用linqz作为查询语言的使用。使用强类型的ObjectContext 为每一个EntitySet暴露属性,使得更加隐 式。
Code
1
Figure8 Query Built Using a Strongly Typed ObjectContext
2
using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
3![](http://img.e-com-net.com/image/product/8bf85857a9e14d23a651e7c8ef856bcc.gif)
![](http://img.e-com-net.com/image/product/eab1c1ad3d6344f98e3a6ee4266d96df.gif)
{
4
// get the latest blog post, with the comments and the people
5
// I'm querying for all the blog posts that are related to this blog.
6
// I want to include the comments and the people who wrote the
7
// comments.
8
// I also want only the most recent posting.
9
// Note: Since we use the EntityKey that is put on the EntityReference
10
// we can either do a tracking query or use span.
11
BlogPost post = (from bp in
12
travelEntities.BlogPosts
13
.Include("Comments.Person")
14
.Include("Blog")
15
where bp.Blog.BlogID == requestedBlog.BlogID
16
orderby bp.BlogDate descending
17
select bp).First();
18
return post;
19
}
20
LINQ to Entities可以看作是很透明的对象服务Object Services,在编程语言里提供直接查询
进而取代以字符串为基础的查询。在这种情况下ObjectQuery实现了IQueryable接口允许采取linq查询表达式,通过entityframework作为一个CCT的查询表达式。
N层开发
在这里阐述用entityframework进行n层开发并不是我的重点,但是伴随edm的发展将彻底解决n层开发的问题因此在这里无法不提到。在edm 1.0版本里,在很多场景中,edm已经很好地支持n层开发,如通过从ObjectContext中attch, detach 和序列化实体等操作在ADO.NET Data Services 和 Windows® Communication Foundation (WCF)已经得到很好的使用。很明显地那些还远远没有达到n层开发的需求。然而那只是开发小组在1.0版本中一种解决方案,在2.0版本中将会添加到其他许多场景中。图9演示了我刚刚阐述的9 ADO.NET Data Services in N-Tier Apps
Code
1
static Uri baseService = new
2
Uri("http://localhost:17338/MyTravelPostService.svc");
3
MyPeople2Entities context = new MyPeople2Entities(baseService);
4
// get the comment that is being marked for deletion
5
// and get the view state blog post.
6
BlogPost post = (BlogPost)ViewState["BlogPost"];
7![](http://img.e-com-net.com/image/product/93a7f0399a9049a3b82d13dcc4073372.gif)
8
// move the comment to the deleted comment selection.
9
Comment deletedComment = post.Comments[e.RowIndex];
10![](http://img.e-com-net.com/image/product/93a7f0399a9049a3b82d13dcc4073372.gif)
11
// call the DeleteComment service
12
context.AttachTo("Comments", deletedComment);
13
context.DeleteObject(deletedComment);
14
DataServiceResponse r = context.SaveChanges();
15![](http://img.e-com-net.com/image/product/93a7f0399a9049a3b82d13dcc4073372.gif)
16
// reload page so that F5, refresh doesn't update all this data.
17
ReloadPage();
18
ADO.NET Data Services是Representational State Transfer (REST)(是每一个资源代表系统中的一个“名词”,一个事物经过一个资源标识符(URI)能被唯一的传递)的一个实现.它通过随心所欲的执行IQueryable使得能够在N层开发中得到应用。在ADO.NET Data Services中你可以做的更多不仅仅是查询实例。ADO.NET Data Services,支持各种HTTP动词,为创建,读取,更新和删除,并提供客户端抽象,以帮助开发执行其解决方案。
第二个应用entityframework进行n层开发的场景是wcf,充分利用从ObjectContext
中
attch ,detach ,serializes
实体的能力。图
10
展示了怎样附加到一个
ObjectContext
Code
1
Figure 10 Attaching to ObjectContext
2
// the creation of the travel MyTravelPostEntities opens the connection
3
// and sets up all the metadata information automatically for you.
4
using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
5![](http://img.e-com-net.com/image/product/8bf85857a9e14d23a651e7c8ef856bcc.gif)
![](http://img.e-com-net.com/image/product/eab1c1ad3d6344f98e3a6ee4266d96df.gif)
{
6
// attach the comment and delete.
7
travelEntities.Attach(deleteComment);
8![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
9
// call delete on the object
10
travelEntities.DeleteObject(deleteComment);
11![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
12
try
13![](http://img.e-com-net.com/image/product/437570a32a8e47669b1b8f34e2a85bac.gif)
{
14
travelEntities.SaveChanges();
15
}
16
catch (OptimisticConcurrencyException opt)
17![](http://img.e-com-net.com/image/product/437570a32a8e47669b1b8f34e2a85bac.gif)
{
18
// catching this exception allows you to
19
// refresh travelEntities with either store/client wins
20
// project the travelEntities into this failed travelEntities.
21
var failedEntities = from e3 in opt.StateEntries
22![](http://img.e-com-net.com/image/product/437570a32a8e47669b1b8f34e2a85bac.gif)
select new
{ e3.Entity };
23![](http://img.e-com-net.com/image/product/b5ccfbfdc70d443ba19cbdc6a5005b86.gif)
24
travelEntities.Refresh(RefreshMode.ClientWins, failedEntities.ToList());
25
travelEntities.SaveChanges();
26
}
27
}
28
默认情况下,任何CLR类产生自edm从vs或使用edmgen.exe(entityframework命令行工具)都是xml序列化,二进制序列化,导航属性的协同关系都作为DataMembers。使得创建ASMX Web services和在viewstate或wcf service中使用entity 实例成为可能。
像其它ORM一样,entityframework现在还不支持用数据操作语言(Data Manipulation Language (DML))进行创建,更新,删除操作。内存中的对象在变化并且建立整个持久化的过程需要多次使用数据库,避免那种状况的途径就是通过使用ObjectContext中的attach方法。使用Attach操作你可以底层知道实体对象已经曾在并且在内存中的操作集合将要被执行。更多的关于用entityframework进行N层开发的信息在不久的msdn中将会被添加。
Just Another ORM?
到目前为止,edm framework一直被很多人认为仅仅是另一个ORM,那也是可以理解的因为只是简单的看了第一版本的edm.目前它已经包含在产品中,对于在一些重要场景中应用已经得到解决,基于这点,许多分析者认为不可能从entity framework中获得所有期望从其他ORM框架欠缺的。
微软在这个方向的投资意味着这将远远超出传统ORM中的ORM产品,我正在讨论的Entity Framework只是更广泛的战略里的第一步。
Edm,正如我在本文开头,为了创建更高层次的域模型那将不仅仅局限于Entity Framework和传统的ORM领域。令人期待的是在未来的发布的产品里Microsoft .NET Framework, Visual Studio, SQL Server®,以及其他微软技术,你将会看到edm的身影。EDM目前首要的影响在于对它的期望和它的整体概念,正与贯穿本文都在讨论的话题关于未来产品的影响。很多决定已经有了明确的意图,如报告服务和分析服务(Reporting Services and Analysis Services)。通过一个共同和一致的域模型能够提供全面的服务,那将会给顾客带来丰厚的利润。在Visual Studio 2008 SP1 中Entity Framework首次实现那个愿景是通过ADO.NET Data Services这个载体,ADO.NET Data Services提供了一种可以接受的开发Representational State Transfer (REST)应用程序方式,它将首次发布的产品(在entityframework之外)就是由edm创建作为它的元数据交换格式。在MIX 2008中微软展示了许多不同的Windows Live ™特性,暴露除了许多他们自己使用ADO.NET Data Services协议和EDM的数据。同样地,正如我们现在就在开始计划下一版本的SQL Server和Visual Studio,开发小组正在努力工作,致力于更好的端到端开发体验和entity framework core