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. java中的字符串相关知识整理

    字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...

  2. 传播正能量——做一个快乐的程序员

    引子 今天在博客园看到施瓦小辛格的文章我们搞开发的为什么会感觉到累,顿时有感而发.自己本来不擅长写文章,更不擅长写这种非技术性的文章,但是在思绪喷薄之际,还是止不住有很多话要说.针对从客观上说&quo ...

  3. svn 常用命令总结

    svn 命令篇 svn pget svn:ignore // 查看忽略项 svn commit -m "提交说明" // 提交修改 svn up(update) // 获取最新版本 ...

  4. [C#] 简单的 Helper 封装 -- SQLiteHelper

    using System; using System.Data; using System.Data.SQLite; namespace SqliteConsoleApp { /// <summ ...

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

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

  6. 原生js+css3实现图片自动切换,图片轮播

    运用CSS3transition及opacity属性 制作图片轮播动画 自己这两天根据用js来控制触发CSS3中transition属性,从而写出来的以CSS3动画为基础,js控制过程的图片轮播 运用 ...

  7. TemplateMethod(模块方法模式)

    /** * 模块模式 * @author TMAC-J * 将一个完整的算法分离,分成不同的模块 * 用于有很多步骤的时候,可能以后这些步骤还会增加,把这些步骤分离 * 将有共性的部分放在抽象类中 * ...

  8. SharePoint 2016 入门视频教程

    之前一直有朋友让自己录一些SharePoint的入门视频,之前没有太多时间,一个巧合的机会收到CSDN学院的邮件,可以在CSDN上发布视频教程,自己就录了一些.说起录视频也是蛮辛苦的,每天下班吃完饭要 ...

  9. Configure a bridge interface over a VLAN tagged bonded interface

    SOLUTION VERIFIED February 5 2014 KB340153 Environment Red Hat Enterprise Linux 6 (All Versions) Red ...

  10. 绿色版的Linux.NET——“Jws.Mono”

    Linux.NET环境的搭建,不仅是一项比较耗时的事情,同时也是一项略显复杂繁琐的事情.特别是对于近期的几个Mono版本,由于官方所提供的源码包中出现代码文件的缺失,这总让我们的付出变得徒劳.另外一方 ...