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. ImageView缩放选项

    ImageView.ScaleType 将图片边界缩放到所在view边界时的缩放选项. Options for scaling the bounds of an image to the bounds ...

  2. CSS浮动、定位

    这几天有空,整理了关于CSS浮动和定位的一些知识点,有什么欠缺的地方,欢迎大家批评指正. 一.文档流的概念指什么?有哪种方式可以让元素脱离文档流? 文档流,指的是元素排版布局过程中,元素会自动从左往右 ...

  3. MySQL设置字段的默认值为当前系统时间

    问题产生: 当我们在对某个字段进行设置时间默认值,该默认值必须是的当前记录的插入时间,那么就将当前系统时间作为该记录创建的时间. 应用场景: 1.在数据表中,要记录每条数据是什么时候创建的,应该由数据 ...

  4. MAVEN学习-第一个Maven项目的构建

    MAVEN安装成功之后就可以进行项目的构建和管理了: 为什么要用maven进行项目的构建和管理? 对于初学者来说一个最直接的也是最容易里的优点在于JAR包的管理,相对于以前开发一个项目的时候我们需要用 ...

  5. Javascript正则对象方法与字符串正则方法总结

    正则对象 var reg = new Regexp('abc','gi') var reg = /abc/ig 正则方法 test方法(测试某个字符串是否匹配) var str = 'abc123'; ...

  6. 三星Note 7停产,原来是吃了流程的亏

    三星Note 7发售两个月即成为全球噩梦,从首炸到传言停产仅仅47天.所谓"屋漏偏逢连天雨",相比华为.小米等品牌对其全球市场的挤压.侵蚀,Galaxy Note 7爆炸事件这场连 ...

  7. Android种使用Notification实现通知管理以及自定义通知栏(Notification示例四)

    示例一:实现通知栏管理 当针对相同类型的事件多次发出通知,作为开发者,应该避免使用全新的通知,这时就应该考虑更新之前通知栏的一些值来达到提醒用户的目的.例如我们手机的短信系统,当不断有新消息传来时,我 ...

  8. Linux命令

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...

  9. Android NDK debug 方法

    最近又频繁遇到 NDK 的错误,记录一下debug调试的一些经验,以备后续查看 一般来说,在Android Studio中的Monitor中将过滤器的 LOG TAG 设置为 "DEBUG& ...

  10. .NET跨平台之旅:将示例站点升级至 .NET Core 1.1 Preview 1

    今天微软发布了 .NET Core 1.1 Preview 1(详见 Announcing .NET Core 1.1 Preview 1 ),紧跟 .NET Core 前进的步伐,我们将示例站点 h ...