11-2. 用”模型定义”函数过滤实体集

问题

想要创建一个”模型定义”函数来过滤一个实体集

解决方案

假设我们已有一个客户(Customer)和票据Invoice)模型,如Figure 11-2所示.

Figure 11-2. Customer and Invoice in a model

我们要想要创建一个”模型定义”函数获取invoice集并过滤出总数高于$300的invoice. 为了更有趣,让我们把一个"模型定义"函数用在一个查询中,这个查询进一步过滤出在5/1/2013之后创建的invoice. 当然,我们想要的是所有customer符合上述条件的invoice.

按下列步骤:

1.在解决方案中右击.edmx 文件,打开方式➤ XML编辑器.

2.在.edmx 文件中概念模型(conceptual models )小区里的<Schema> 标签下插入Listing 11-3所示的代码.

Listing 11-3. The GetInvoices() Model-Defined Function

<Function Name="GetInvoices" ReturnType="Collection(EFRecipesModel1102.Invoice)" >

<Parameter Name="invoices" Type="Collection(EFRecipesModel1102.Invoice)">

</Parameter>

<DefiningExpression>

Select VALUE i from invoices as i where i.Amount > 300M

</DefiningExpression>

</Function>

3.插入和查询模型的代码,如Listing 11-4所示的代码:

Listing 11-4.用eSQL 和LINQ两种方式用GetInvoices()方法(“模型定义”函数)来查询模型

class Program

{

static void Main(string[] args)

{

RunExample();

}

static void RunExample()

{

using (var context = new EFRecipesEntities1102())

{

DateTime d1 = DateTime.Parse("8/8/2013");

DateTime d2 = DateTime.Parse("8/12/2012");

var c1 = new Customer { Name = "Jill Robinson", City = "Dallas" };

var c2 = new Customer { Name = "Jerry Jones", City = "Denver" };

var c3 = new Customer { Name = "Janis Brady", City = "Dallas" };

var c4 = new Customer { Name = "Steve Foster", City = "Dallas" };

context.Invoices.Add(new Invoice

{

Amount = 302.99M,

Description = "New Tires",

Date = d1,

Customer = c1

});

context.Invoices.Add(new Invoice

{

Amount = 430.39M,

Description = "Brakes and Shocks",

Date = d1,

Customer = c2

});

context.Invoices.Add(new Invoice

{

Amount = 102.28M,

Description = "Wheel Alignment",

Date = d1,

Customer = c3

});

context.Invoices.Add(new Invoice

{

Amount = 629.82M,

Description = "A/C Repair",

Date = d2,

Customer = c4

});

context.SaveChanges();

}

using (var context = new EFRecipesEntities1102())

{

Console.WriteLine("Using eSQL query...");

string sql = @"Select value i from

EFRecipesModel1102.GetInvoices(EFRecipesEntities1102.Invoices) as i

where i.Date > DATETIME'2013-05-1 00:00'

and i.Customer.City = @City";

var objectContext = (context as IObjectContextAdapter).ObjectContext;

var invoices = objectContext.CreateQuery<Invoice>(sql,

new ObjectParameter("City", "Dallas")).Include("Customer");

foreach (var invoice in invoices)

{

Console.WriteLine("Customer: {0}\tInvoice for: {1}, Amount: {2}",

invoice.Customer.Name, invoice.Description, invoice.Amount);

}

}

using (var context = new EFRecipesEntities1102())

{

Console.WriteLine();

Console.WriteLine("Using LINQ query...");

DateTime date = DateTime.Parse("5/1/2013");

var invoices = from invoice in

MyFunctions.GetInvoices(context.Invoices)

where invoice.Date > date

where invoice.Customer.City == "Dallas"

select invoice;

foreach (var invoice in ((DbQuery<Invoice>)invoices)

.Include("Customer"))

{

Console.WriteLine("Customer: {0}, Invoice for: {1}, Amount: {2}",

invoice.Customer.Name, invoice.Description, invoice.Amount);

}

}

Console.WriteLine("\nPress any key to exit...");

Console.ReadKey();

}

}

public class MyFunctions

{

[EdmFunction("EFRecipesModel1102", "GetInvoices")]

public static IQueryable<Invoice> GetInvoices(IQueryable<Invoice> invoices)

{

return invoices.Provider.CreateQuery<Invoice>(

Expression.Call((MethodInfo)MethodInfo.GetCurrentMethod(),

Expression.Constant(invoices,typeof(IQueryable<Invoice>))));

}

}

代码Listing 11-4的输出结果如下:

Using eSQL for the query...

Customer: Jill Robinson Invoice for: New Tires, Amount: 302.99

Using LINQ for the query...

Customer: Jill Robinson, Invoice for: New Tires, Amount: 302.99

它是如何工作的?

从我们定义的Listing 11-3所示的GetInvoices()函数, 我们可以看到它接受一个Invoice集,并返回一个Invoice集.在运行时里,会解释为接受一个 IQueryable<Invoice> 并返回一个IQueryable<Invoice>.

在 eSQL表达式里, 我们把GetInvoices() 函数用在  from 子句里. 我们传递进去未过滤的Invoice集,然后我们的GetInvoices() 函数会返回一个过滤后的Invoice集. 我们进一步根据日期和Customer所有城市,用Where子句过滤这个集合. 接着我们用CreateQuery<Invoice>()来创建ObjectQuery<Invoice>类型. 在创建的查询里, 我们传递一个参数(客户所在的城市)来过滤并使用Include()方法来包含相关联的customer.一旦我们有了ObjectQuery<Invoice>, 我们遍历这个结果集并且过滤后符合条件的invoice打印出来.

用 LINQ 查询, 要有趣一些,我们把GetInvoices()方法放在了表达式的Form子句里,并把结果再根据日期和城市进行过滤(这点类似于eSQL表达式).然而,为了在LINQ查询中使用我们的函数,我们需要实现一个运行时方法,它接受一个IQueryable<Invoice> 并返回一个IQueryable<Invoice>.

与11-1小节里用”模型定义”函数返回一个标量值的方法存根不同,此处我们必须实现方法.创建该方法通常是参考引导程序

下面是引导程序的几个规则:

•如果"模型定义"函数返回一个IQueryable<T>,必须使用引导程序

• 当一个函数返回一个IQueryable<T>,但不是接受一个IQueryable<T>, 引导方法必须实现为ObjectContext类的一部分

因为第二条规则,所以我们的ObjectContext在没有用一个IQueryable<T>开始的情况下,我们也不能返回一个IQueryable<T>.但我们可以传递进去一个IQueryable<T>, 接着在我们的引导方法里执行一些操作使它返回一个相关的IQueryable<T>. 尽管,我们不能在ObjectContext类以外手工创建一个IQueryable<T>,但像我们的例子里,我们接收一个IQueryable<T>作为参数后,可以为我们的ObjectContext在类外实现引导代码.

在我们实现的引导方法里,我们得到一个IQueryable<Invoice>.可以通过它的的Provider 属性得到一个IqueryProvider实例, IQueryProvider.CreateQuery<Invoice>()允许我们把IQueryable<T>加到表达树上

.当然此方法我们也使用了相关的”函数”特性来修饰,并传入一个invoice集.

附:创建示例用到的数据库的脚本文件

Entity Framework 6 Recipes 2nd Edition(11-2)译 -> 用”模型定义”函数过滤实体集的更多相关文章

  1. Entity Framework 6 Recipes 2nd Edition 译 -> 目录 -持续更新

    因为看了<Entity Framework 6 Recipes 2nd Edition>这本书前面8章的翻译,感谢china_fucan. 从第九章开始,我是边看边译的,没有通读,加之英语 ...

  2. Entity Framework 6 Recipes 2nd Edition(11-1)译 -> 从“模型定义”函数返回一个标量值

    第11章函数 函数提供了一个有力代码复用机制, 并且让你的代码保持简洁和易懂. 它们同样也是EF运行时能利用的数据库层代码.函数有几类: Rowset Functions, 聚合函数, Ranking ...

  3. Entity Framework 6 Recipes 2nd Edition(11-2)译 -> 为一个”模型定义”函数返回一个计算列

    11-3. 为一个”模型定义”函数返回一个计算列 问题 想从”模型定义”函数里返回一个计算列 解决方案 假设我们有一个员工(Employee)实体,属性有: FirstName, LastName,和 ...

  4. Entity Framework 6 Recipes 2nd Edition(9-3)译->找出Web API中发生了什么变化

    9-3. 找出Web API中发生了什么变化 问题 想通过基于REST的Web API服务对数据库进行插入,删除和修改对象图,而不必为每个实体类编写单独的更新方法. 此外, 用EF6的Code Fri ...

  5. Entity Framework 6 Recipes 2nd Edition(9-4)译->Web API 的客户端实现修改跟踪

    9-4. Web API 的客户端实现修改跟踪 问题 我们想通过客户端更新实体类,调用基于REST的Web API 服务实现把一个对象图的插入.删除和修改等数据库操作.此外, 我们想通过EF6的Cod ...

  6. Entity Framework 6 Recipes 2nd Edition(目录索引)

    Chapter01. Getting Started with Entity Framework / 实体框架入门 1-1. A Brief Tour of the Entity Framework ...

  7. Entity Framework 6 Recipes 2nd Edition(9-1)译->用Web Api更新单独分离的实体

    第九章 在N层结构的应用程序中使用EF 不是所有的应用都能完全地写入到一个单个的过程中(就是驻留在一个单一的物理层中),实际上,在当今不断发展的网络世界,大量的应用程序的结构包含经典的表现层,应用程, ...

  8. Entity Framework 6 Recipes 2nd Edition(13-2)译 -> 用实体键获取一个单独的实体

    问题 不管你用DBFirst,ModelFirst或是CodeFirst的方式,你想用实体键获取一个单独的实体.在本例中,我们用CodeFirst的方式. 解决方案 假设你有一个模型表示一个Paint ...

  9. Entity Framework 6 Recipes 2nd Edition(13-3)译 -> 为一个只读的访问获取实体

    问题 你想有效地获取只是用来显示不会更新的操作的实体.另外,你想用CodeFirst的方式来实现 解决方案 一个非常常见行为,尤其是网站,就是只是让用户浏览数据.大多数情况下,用户不会更新数据.在这种 ...

随机推荐

  1. 猫哥网络编程系列:HTTP PEM 万能调试法

    注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...

  2. ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件

    虽然ASP.NET Core应用的路由是通过RouterMiddleware这个中间件来完成的,但是具体的路由解析功能都落在指定的Router对象上,不过我们依然有必要以代码实现的角度来介绍一下这个中 ...

  3. jQuery学习之路(1)-选择器

    ▓▓▓▓▓▓ 大致介绍 终于开始了我的jQuery学习之路!感觉不能再拖了,要边学习原生JavaScript边学习jQuery jQuery是什么? jQuery是一个快速.简洁的JavaScript ...

  4. 操作系统篇-hello world(免系统运行程序)

     || 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.前言     今天起开始分享关于操作系统的相关知识,本人也是菜鸟一个,正处于学习阶段,这整个操作系统篇也是我边学习边总结的一些结果,希 ...

  5. DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(3)

    上一篇:<DDD 领域驱动设计-谈谈 Repository.IUnitOfWork 和 IDbContext 的实践(2)> 这篇文章主要是对 DDD.Sample 框架增加 Transa ...

  6. javascript中变量提升的理解

    网上找了两个经典的例子 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); // 10 var ...

  7. 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.1

    HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...

  8. NodeJs支付宝移动支付签名及验签

    非常感谢 :http://www.jianshu.com/p/8513e995ff3a?utm_campaign=hugo&utm_medium=reader_share&utm_co ...

  9. linux下mono的安装与卸载

    我很遗憾的告诉你,这里没有安装,为什么标题里加入安装俩字呢,因为如果不加的话你会搜到这篇文章吗?哈哈!别气馁,这里会给你些安装的tips! 源码安装,git安装:建议安装路径如下,至于为什么,我也讲不 ...

  10. deepsooncms在Ubuntu 14.04上部署教程

    deepsooncms在Ubuntu 14.04上部署教程 一.安装mono1.在命令行运行sudo apt-key adv --keyserver keyserver.ubuntu.com --re ...