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. C# DateTime与时间戳转换

    C# DateTime与时间戳的相互转换,包括JavaScript时间戳和Unix的时间戳. 1. 什么是时间戳 首先要清楚JavaScript与Unix的时间戳的区别: JavaScript时间戳: ...

  2. SQL Server 致程序员(容易忽略的错误)

    标签:SQL SERVER/MSSQL/DBA/T-SQL好习惯/数据库/需要注意的地方/程序员/容易犯的错误/遇到的问题 概述 因为每天需要审核程序员发布的SQL语句,所以收集了一些程序员的一些常见 ...

  3. Xcode模拟器启动不了,修复ios模拟器

    1.如果可以重置模拟器 首先试试重置模拟器 2.如果不能重置,可以选择使用如下命令杀死模拟器服务: killall -9 com.apple.CoreSimulator.CoreSimulatorSe ...

  4. Javascript 代理模式模拟一个文件同步功能

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. .NET中AOP方便之神SheepAspect

    SheepAspect 简介以及代码示列: SheepAspect是一个AOP框架为.NET平台,深受AspectJ.它静织目标组件作为一个编译后的任务(编译时把AOP代码植入). 多有特性时,可根据 ...

  6. winform 窗体圆角设计

    网上看到的很多winform窗体圆角设计代码都比较累赘,这里分享一个少量代码就可以实现的圆角.主要运用了System.Drawing.Drawing2D. 效果图 代码如下. private void ...

  7. BPM配置故事之案例13-触发消息通知

    老李:小明! 小明:--见你就没好事,又要我干嘛? 老李:额,小事小事,最近很多部门都觉得Boss的审批速度太慢了,能不能以后给审批人一个消息提醒? 小明:--有一种不太好的预感 老李:怎么,很困难么 ...

  8. xss和sql注入原理学习

    8.4 Web跨站脚本攻击 8.4.1  跨站脚本攻击的原理(1) 跨站脚本在英文中称为Cross-Site Scripting,缩写为CSS.但是,由于层叠样式表 (Cascading Style ...

  9. 一不小心写了个WEB服务器

    开场 Web服务器是啥玩意? 是那个托管了我的网站的机器么? No,虽然那个也是服务器,但是我们今天要说的Web服务器主要是指像IIS这样一类的,用于处理request并返回response的工具,没 ...

  10. 使用ENode框架前您需要了解的东西(初稿)

    选择ENode意味着什么可能很多人还不太清楚.我简单整理了一下: 意味着你选择了:你需要做DDD领域建模.选择了事件驱动的架构.选择了CQRS架构.选择了最终一致性.选择了事件溯源.选择了分布式.这些 ...