提示42. 怎样使用Code-Only创建一个动态模型

背景:

当我们给出使用Code-Only的例子,总是由创建一个继承自ObjectContext的强类型的Context开始。这个类用于引导模型。

例如这个类(处于简化问题考虑省略了属性体):

1 public class MyContext : ObjectContext
2 {
3 public ObjectSet<Category> Categories { get; }
4 public ObjectSet<Product> Products { get; }
5 }

这告诉CodeOnly使用2个EntitySet,一个称作CategoriesCategory实体的集合与一个称作ProductsProduct实体的集合,来引导一个模型。

然后如果需要你将来可以通过操作ContextBuilder来改进这个模型。

问题:

但是如果你没有一个强类型的Context类呢?

如果你决定在运行时需要一个模型,但没有一个适合的强类型Context类可以使用。

在今天早些时候一个客户恰好问我这个问题。

解决方案:

最终你可以直接使用ObjectContext。当你通过Code-Only做这个工作时对模型一无所知。但是这不是那么糟糕,所有你需要做的就是明确的告诉Code-Only通常可以由强类型context了解到的所有信息。

例如这个:

1 public ObjectSet<Person> People { get; }

可以被转换为这个:

1 var builder = new ContextBuilder<ObjectContext>();
2 builder.RegisterSet<Person>(“People”);

有趣吗?

结尾的例子:

这个例子,演示完全不使用强类型ObjectContext下将一个Person对象(BillG)存储到数据库并再次检索出来:

首先是Person类(这是个POCO):

1 public class Person
2 {
3 public int ID { get; set; }
4 public string Firstname { get; set; }
5 public string Surname { get; set; }
6 }

接下来是建立ObjectContext的代码:

 1 // Create the contextbuilder, and tell it about the People set.
2 var builder = new ContextBuilder<ObjectContext>();
3 builder.RegisterSet<Person>("People");
4 // Create a connection
5 string connstr = @"Data Source=.\SQLEXPRESS;Initial Catalog=PeopleDb;Integrated Security=True;Pooling=False;MultipleActiveResultSets=True";
6 var conn = new SqlConnection(connstr);
7
8 // Create an ObjectContext from the builder
9 using (ObjectContext ctx = builder.Create(conn))
10 {
11 // Create the database if it doesn’t already exist
12 if (!ctx.DatabaseExists())
13 ctx.CreateDatabase();
14
15 // Create Bill
16 Person p = new Person {
17 ID = 1,
18 Firstname = "Bill",
19 Surname = "Gates"
20 };
21
22 // Add Bill to the context
23 // UPDATE: thanks to danny for the simplification
24 ctx.CreateObjectSet<Person>().AddObject(p);
25 using the general purpose
26 // AddObject method.
27 // The only tricky part is the EntitySet name with must
28 // be qualified with the the container name,
29 // in this case is ObjectContext.
30 ctx.AddObject("ObjectContext.People", p);
31 ctx.SaveChanges();
32 // Issue a query against the People set.
33 var bill = (from person in ctx.CreateObjectSet<Person>()
34 where person.Firstname == "Bill"
35 select person).Single();
36 // Make and Save a change.
37 bill.Firstname = "William";
38 ctx.SaveChanges();
39 }

就不是强类型的而论这非常简单了。

提示43. 怎样通过一个Data Service的验证

问题:

当我们编写访问一个Data Service的代码,如SharePoint,客户端程序必须提供一系列有效的凭据,否则你将收到一个”401 Unauthorized”的响应。

针对与DataServie宿主在同一网站上的Silverlight应用,通常会自动处理好这个问题。

但对于如WPF应用,这需要手动处理。

解决方案:

这个解决方案在你执行任何查询或更新之前在DataServieContext上设置凭证属性,像这样:

1 Uri uri = new Uri("http://mflasko-dev/_vti_bin/listdata.svc"));
2 TeamSiteDataContext ctx = new TeamSiteDataContext(uri);
3 ctx.Credentials = System.Net.CredentialCache.DefaultCredentials;
4 …

就是这样。

当然如果需要你可以提供另一套凭证信息,但是一般来说,DefaultCredentials就是你想要的。

提示44. 怎样导航到一个Odata兼容服务

最近我做了一个关于Data Service与Odata的速成课程。

在这个过程中我发现我的笔记可能对大家有用。

这里给出我的备忘单供你快速掌握Odata Url。

注意:Odata服务可能未必完全支持下面这些特性:但是如果它们支持,这就是你使用它们的方法。

服务:

所有服务由一个宿主于某一地方的Data Service开始:

http://server/service.svc

基本查询:

通过资源集(resource set)来访问Data Service实体,像这样:

http://server/service.svc/People

使用主键来请求一个指定的实体,像这样:

http://server/service.svc/People(16)

或通过使用一个到你知道的对象的关联引用:

http://server/service.svc/People(16)/Mother

这请求16号人的母亲。

一旦你可以识别出一个实体,你可以直接导航到它的属性:

http://server/service.svc/People(16)/Mother/Firstname

$value:

但是上一个查询将属性值包在XML中,如果你仅想要单纯的属性值,可以像这样在url后面附加一个$value:

http://server/service.svc/People(16)/Mother/Firstname/$value

$filter:

你可以使用$filter来过滤资源集:

http://server/service.svc/People?$filter=Firstname  eq ‘Fred’

注意过滤条件字符串中使用单引号。

而数字不需要引号:

http://server/service.svc/Posts?$filter=AuthorId eq 1

要按时间过滤你需要在过滤条件中标识出时间,如下:

http://server/service.svc/Posts?$filter=CreatedDate eq DateTime'2009-10-31'

也可以通过关联引用来过滤:

http://server/service.svc/People?$filter=Mother/Firstname eq 'Wendy'

你可以在过滤条件中使用的基本运算符:

Operator

Description

C# equivalent

eq

equals

==

ne

not equal

!=

gt

greater than

>

ge

greater than or equal

>=

lt

less than

<

le

less than or equal

<=

and

and

&&

or

or

||

()

grouping

()

如果需要还有一系列可以在过滤条件中使用的函数。

$expand:

如果你想在结果中包含相关项目,像这样使用$expand:

http://server/service.svc/Blogs?$expand=Posts

这将返回匹配的Blogs及每个Blog的post。

$select:

一些Data Service允许你将结果限制在仅你需要的属性 – 又称投影 – 例如如果你仅想要匹配Post的Id与Title,你需要如下这样的Url:

http://server/service.svc/Posts?$select=Id,Title

你甚至也可以映射到关联对象的属性,如这样:

http://server/service.svc/Posts?$expand=Blog&$select=Id,Title,Blog/Name

这仅映射到了每个Post的 Id,Title与Blog的名称。

$count:

如果你仅想知道将返回多少条记录,而不检索它们,你需要使用$count:

http://server/service.svc/Blogs/$count

注意$count成为URL的片段之一-它不是查询字符串的一部分-所以如果你想与另一个操作如$filter合并,你需要将$count放在前面,像这样:

http://server/service.svc/Posts/$count?$filter=AuthorId eq 6

这个查询返回作者是6号person的帖子的数量。

$orderby:

如果你需要结果是排序过的,可以使用$orderby:

http://server/service.svc/Blogs?$orderby=Name

返回的结果是升序排序,要进行降序排序你需要:

http://server/service.svc/Blogs?$orderby=Name%20desc

要首先按一个属性排序,然后按另一个属性排序,你需要:

http://server/service.svc/People?$orderby=Surname,Firstname

如果需要也可以在其中加入desc。

$top:

如果你仅想要前10条项目,可以像这样使用$top:

http://server/service.svc/People?$top=10

$skip

如果你仅对某一页数的数据感兴趣,你需要联合使用$top与$skip:

这告诉Data Service跳过前20条匹配结果并返回下10条数据。当每页有10个项而你需要显示第3页结果时这很有用。

注意:通常将$top&$skip与$orderby合并使用是一个好主意,以保证由底层数据源检索到的结果的顺序是一致的。

$inlinecount&$skiptoken:

使用$top与$skip允许客户端控制分页。

但是服务器也需要一种方法来控制分页-以最小化服务初级用户及那些恶意用户所需的负载-OData协议通过Server Driven Paging(服务器驱动的分页)来完成这个任务。

当Server Driven Paging开启后,即使客户端请求所有记录,但它们将只会得到一个页的结果。

正如你想象,这会给客户端应用开发人员带来一点麻烦。

如果客户端需要知道到底有多少结果,它们可以在查询后追加$inlinecount选项,如下:

http://server/service.svc/People?$inlinecount=allpages

结果将会“内联”包含一个总数,及一个服务器生成的用于获取下一页结果的url。

这个服务器生成的url包含一个$skiptoken,这与一个游标或书签等效,以通知服务器由哪重新开始:

http://server/service.svc/People?$skiptoken=4

$links

有时候你只需得到与实体关联的一个特殊实体的url,这时候就用到$links了:

http://server/service.svc/Blogs(1)/$links/Posts

这告诉Data Service返回Blog1相关的所有Posts的链接-即url。

$metadata

如果你需要知道一个Odata兼容的数据服务暴露的模型的信息,你可以通过在服务的根路径后面拼接一个$metadata选项,如下:

http://server/service.svc/$metadata

这将返回一个Data Service暴露的包含概念模型(又称EDM)的EDXM文件。

总结

这会帮助你早日上手。

我将更多的探索Data Service与Odata,我也将与你分享我的所学,请锁定我的博客。

提示45. 怎样在运行时置换EF元数据

背景:

默认情况下Entity Framework将它的元数据作为一个资源嵌入程序集中。

同时它也将一个引用了这些资源连接字符串放入App或Web配置文件中,像这样:

1 <add name="BloggingEntities" connectionString="metadata=res://*/Blogging.csdl|res://*/Blogging.ssdl|res://*/Blogging.msl;provider=System.Data.SqlClient;
2 provider connection string=&quot;Data Source=.\SQLEXPRESS;Initial Catalog=TipsDatabase;Integrated Security=True;MultipleActiveResultSets=True&quot;"
3 providerName="System.Data.EntityClient" />

这使其可以很容易的开始:

1 using (BloggingEntities ctx = new BloggingEntities())
2 {

注意:使用res://*告诉EF在程序集资源内部查找各种各样的元数据。

问题

但是将元数据嵌入作为资源同时意味着它本质上是不可改变的。

假如你需要在运行时更改它怎么办呢?

有很多原因是你想要在运行时更改元数据,但是也许最可能的原因是在生产环境你不得不配合有一套不同数据库设计想法的DBA。

一般情况下这意味着你不得不由于数据库的更改来更改一部分存储模型(SSDL)与映射(MSL)。

这样做完全可以,事实上这是使用Entity Framework的一大好处,只要概念模型或者称CSDL—开发的程序所依赖的东西—保持不变。

解决方案

所以怎样在运行时插入一个不同的MSL与SSDL呢?

下面是相关的步骤:

步骤1:

得到’元数据项目’:

1. 在设计器画布上右击,点击属性:

2. 将’元数据项目处理’设置为’ 复制到输出目录’:

3. 生成项目,查看bin\debug(或bin\release)目录:

步骤2:

现在你有了文件形式的CSDL/MSL/SSDL,很容易替换其中一个或多个(一般是SSDL与MSL)为与你环境匹配的版本。所以你可以有两套,其一用于开发环境,另一套用于生成环境。

然后你需要做的仅是修改你的连接字符串来指向正确的文件集,类似下面这样:

 1 var connStr =
2 @"metadata=.\Blogging.csdl|.\Production.ssdl|.\Production.msl;
3 provider=System.Data.SqlClient;
4 provider connection string=""
5 Data Source=.\SQLEXPRESS;
6 Initial Catalog=TipsDatabase;
7 Integrated Security=True;
8 MultipleActiveResultSets=True
9 """;
10
11 using (BloggingEntities ctx = new BloggingEntities(connStr))
12 {

注意现在使用的连接字符串不是res://而是.\,这告知EF在与应用程序相同的目录下查找元数据。

事情就是这样。

Entity Framework技巧系列之十一 - Tip 42 - 45的更多相关文章

  1. Entity Framework技巧系列之十三 - Tip 51 - 55

    提示51. 怎样由任意形式的流中加载EF元数据 在提示45中我展示了怎样在运行时生成一个连接字符串,这相当漂亮. 其问题在于它依赖于元数据文件(.csdl .ssdl .msl)存在于本地磁盘上. 但 ...

  2. (翻译)Entity Framework技巧系列之十 - Tip 37 - 41

    提示37. 怎样进行按条件包含(Conditional Include) 问题 几天前有人在StackOverflow上询问怎样进行按条件包含. 他们打算查询一些实体(比方说Movies),并且希望预 ...

  3. Entity Framework技巧系列之十 - Tip 37 - 41

    提示37. 怎样进行按条件包含(Conditional Include) 问题 几天前有人在StackOverflow上询问怎样进行按条件包含. 他们打算查询一些实体(比方说Movies),并且希望预 ...

  4. Entity Framework技巧系列之二 - Tip 6 - 8

    提示6. 如何及何时使用贪婪加载 什么时候你需要使用贪婪加载? 通常在你的程序中你知道对查询到的实体将要进行怎样的操作. 例如,如果你查询一个订单以便为一个客户重新打印,你知道没有组成订单的项目即产品 ...

  5. Entity Framework技巧系列之九 - Tip 35 - 36

    提示35. 怎样实现OfTypeOnly<TEntity>()这样的写法 如果你编写这样LINQ to Entities查询: 1 var results = from c in ctx. ...

  6. Entity Framework技巧系列之五 - Tip 16 – 19

    提示16. 当前如何模拟.NET 4.0的ObjectSet<T> 背景: 当前要成为一名EF的高级用户,你确实需要熟悉EntitySet.例如,你需要理解EntitySet以便使用 At ...

  7. Entity Framework技巧系列之六 - Tip 20 – 25

    提示20. 怎样处理固定长度的主键 这是正在进行中的Entity Framework提示系列的第20篇. 固定长度字段填充: 如果你的数据库中有一个固定长度的列,例如像NCHAR(10)类型的列,当你 ...

  8. Entity Framework技巧系列之十四 - Tip 56

    提示56. 使用反射提供程序编写一个OData Service 在TechEd我收到一大堆有关将数据作为OData暴露的问题. 到目前为止你大概知道可以使用数据服务与Entity Framework将 ...

  9. Entity Framework技巧系列之十二 - Tip 46 - 50

    提示46. 怎样使用Code-Only排除一个属性  这次是一个真正简单的问题,由StackOverflow上这个问题引出.  问题:  当我们使用Code-Only把一个类的信息告诉Entity F ...

随机推荐

  1. Hive 安装过程中的问题

    org.apache.thrift.transport.TTransportException: Could not create ServerSocket on address 0.0.0.0/0. ...

  2. winsock编程IOCP模型实现代码

    winsock编程IOCP模型实现代码 话不多说,上代码.借鉴<windows核心编程>部分源码和CSDN小猪部分代码. stdafx.h依赖头文件: #include <iostr ...

  3. sqlserver2012评估期已过问题处理

    于之前安装sqlserver2012忘记输入序列号,现在出现评估期已过的问题,网上忙活半天,才解决,发现网上叙述都很凌乱,而且只有大意,新手很难操作,所以把我操作的过程分享给大家 步骤阅读   百度经 ...

  4. Oracle中 union 和 union all 的区别

    如果我们需要将两个select语句的结果作为一个整体显示出来,我们就需要用到union或者union all关键字. union(或称为联合)的作用是将多个结果合并在一起显示出来. union和uni ...

  5. Apache环境服务器配置Let's Encrypt免费SSL证书及自动续期方法

    如今越来越多的网站开始使用SSL证书,实现HTTPS网址形式,如果我们是英文网站更需要用到这样格式的HTTPS网址,因为根据谷歌搜索结果提示到如果用到SSL证书的在同等条件下排名结果是有靠前可能的.我 ...

  6. HDU 5863 cjj's string game

    $dp$,矩阵加速. 设$dp[i][j][0]$表示:长度为$i$的两个字符串,之前还未出现过长度为$m$相同的,目前为止最后$j$个是相同的. 设$dp[i][j][1]$表示:长度为$i$的两个 ...

  7. 第七十九,CSS3背景渐变效果

    CSS3背景渐变效果 学习要点: 1.线性渐变 2.径向渐变 本章主要探讨HTML5中CSS3背景渐变功能,主要有两种渐变方式:线性渐变和径向 (放射性)渐变. 一.线性渐变 linear-gradi ...

  8. Sass入门:第二章

    1.Sass语法格式 假设有这样一段CSS代码: body{ font : 100% Helvetica , sans-serif; color : #333; } Sass最初的语法格式 $font ...

  9. webstorm常用快捷键及(idea,phpstorm,android studio通用)使用技巧

    webstorm常用快捷键 ctrl+l 格式化代码 ctrl+shift+ -/+键   折叠/展开所有代码 打开file:ctrl+shift+n 打开一个类:ctrl+n 代码提示:Ctrl+a ...

  10. 简单的Socket通信

    Socket简介 Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求. 服务端步骤: • socket:创建服务器socket ...