11-6.从一个”模型定义”函数里返回一个复杂类型

问题

想要从一个”模型定义”函数返回一个复杂类型

解决方案

假设我们有一个病人(patient)和他们访客(visit)的模型,如 Figure 11-6所示 .

Figure 11-6. A model for patient visits

我们想要创建一个”模型定义”函数,返回一个概要信息,包括:病人名字,病人的访客数,和病人累积的账单. 此外,我们只过滤出年龄超过40岁的病人:

1. 在模型设计视图上,右击, 新建 ➤ 复杂类型.

2.在模型浏览器里右击新建的复杂类型,重命名为VisitSummary, 然后给复杂属性添加下列属性::

a. Name: String,不可为null

b. TotalVisits: Int32, 不可为null

c. TotalCost:Decimal, 不可为null

3. 在解决方案资源管理器中右击.edmx 文件, 打开方式 ➤ XML 编辑器.

4. 在.edmx 文件的概念模型conceptual models)的<Schema> 标签下插入Listing 11-11所示的代码,这样函数主定义好了.

 Listing 11-11. The GetVisitSummary() Model-Defined Function

<Function Name="GetVisitSummary"  ReturnType="Collection(EFRecipesModel.VisitSummary)">

<DefiningExpression>

select VALUE EFRecipesModel.VisitSummary(pv.Patient.Name,

Count(pv.VisitId),Sum(pv.Cost))

from EFRecipesEntities.PatientVisits as pv

group by pv.Patient.Name

</DefiningExpression>

</Function>

5. 用如 Listing 11-12.所示的代码来插入和查询这个模型:

Listing 11-12. Using eSQL and LINQ with the VisitSummary() Function to Query the Model

class Program

{

static void Main(string[] args)

{

RunExample();

}

static void RunExample()

{

using (var context = new EFRecipesEntities())

{

string hospital = "Oakland General";

var p1 = new Patient { Name = "Robin Rosen", Age = 41 };

var p2 = new Patient { Name = "Alex Jones", Age = 39 };

var p3 = new Patient { Name = "Susan Kirby", Age = 54 };

var v1 = new PatientVisit

{

Cost = 98.38M,

Hospital = hospital,

Patient = p1

};

var v2 = new PatientVisit

{

Cost = 1122.98M,

Hospital = hospital,

Patient = p1

};

var v3 = new PatientVisit

{

Cost = 2292.72M,

Hospital = hospital,

Patient = p2

};

var v4 = new PatientVisit

{

Cost = 1145.73M,

Hospital = hospital,

Patient = p3

};

var v5 = new PatientVisit

{

Cost = 2891.07M,

Hospital = hospital,

Patient = p3

};

context.Patients.Add(p1);

context.Patients.Add(p2);

context.Patients.Add(p3);

context.SaveChanges();

}

using (var context = new EFRecipesEntities())

{

Console.WriteLine("Query using eSQL...");

var esql = @"Select value ps from EFRecipesEntities.Patients

as p join EFRecipesModel.GetVisitSummary()

as ps on p.Name = ps.Name where p.Age > 40";

var objectContext = (context as IObjectContextAdapter).ObjectContext;

var patients = objectContext.CreateQuery<VisitSummary>(esql);

foreach (var patient in patients)

{

Console.WriteLine("{0}, Visits: {1}, Total Bill: {2}",

patient.Name, patient.TotalVisits.ToString(),

patient.TotalCost.ToString("C"));

}

}

using (var context = new EFRecipesEntities())

{

Console.WriteLine();

Console.WriteLine("Query using LINQ...");

//译注:遇到了与11-5一样的异常

var patients = from p in context.Patients

join ps in context.GetVisitSummary() on p.Name equals

ps.Name

where p.Age >= 40

select ps;

foreach (var patient in patients)

{

Console.WriteLine("{0}, Visits: {1}, Total Bill: {2}",

patient.Name, patient.TotalVisits.ToString(),

patient.TotalCost.ToString("C"));

}

}

}

}

partial class EFRecipesEntities

{

[EdmFunction("EFRecipesModel", "GetVisitSummary")]

public IQueryable<VisitSummary> GetVisitSummary()

{

var objectContext = (this as IObjectContextAdapter).ObjectContext;

return objectContext.CreateQuery<VisitSummary>(

Expression.Call(Expression.Constant(this),

(MethodInfo)MethodInfo.GetCurrentMethod()).ToString());

}

}

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

Query using eSQL...

Robin Rosen, Visits: 2, Total Bill: $1,221.36

Susan Kirby, Visits: 2, Total Bill: $4,036.80

Query using LINQ...

Robin Rosen, Visits: 2, Total Bill: $1,221.36

Susan Kirby, Visits: 2, Total Bill: $4,036.80

它是如何工作的?

我们先在模型里添加一个复杂类型,接着创建如Listing 11-11的GetVisitSummary() 函数,它能返回包含这个新建的复杂类型的集合.注意:复杂类型的构造函数接受参数的顺序要与我们定义它的属性时的顺序一致. 你可能需要检查.edmx文件,确保设计器按我们添加的顺序是一致.

由于我们函数返回IQueryable<VisitSummary>, 所以我们需要实现引导代码. 同样,因为我们需要访问ObjectContext的QueryProvider,所以我们需要在EFRecipesEntities类中实现运行时方法.

如果我们把这个函数用在LINQ查询中,你可能需要让这个方法返回IQueryable<DbDataRecord>给匿名类型.虽然我们的这个集合不能进一步过滤,但是包含复杂类型的集合是可以被进一点过滤的.

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

Entity Framework 6 Recipes 2nd Edition(11-6)译 -> 从一个”模型定义”函数里返回一个复杂类型的更多相关文章

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

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

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

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

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

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

  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(9-7)译->在WCF服务中序列化代理

    9-7. 在WCF服务中序列化代理 问题 从一个查询里返回一个动态代理对象,想要把它序列为一个POCO(Plain-Old CLR Objects)对象. 实现基于POCO实体对象, 在运行时,EF会 ...

  7. Entity Framework 6 Recipes 2nd Edition(12-8)译 -> 重新获取一个属性的原始值

    12-8. 重新获取一个属性的原始值 问题 在实体保存到数据库之前,你想重新获取属性的原始值 解决方案 假设你有一个模型 (见 Figure 12-11) 表示一个员工( Employee),包含工资 ...

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

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

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

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

随机推荐

  1. Hangfire项目实践分享

    Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...

  2. static,你还敢用吗?(二)

    为了压系统,昨天小组在测试环境模拟了一大批订单数据.今天上午查看记录的账单计息日志,发现了一大堆的MySqlException MySql.Data.MySqlClient.MySqlExceptio ...

  3. 按需加载.js .css文件

    首先,理解按需加载当你需要用到某个js里面的函数什么鬼,或者某个css里的样式的时候你才开始加载这个文件. 然后是怎样实现的,简单来说就是在js中动态的createElem<script> ...

  4. Sublime的使用

    1.一个可扩展性强的编辑工具 2.如何安装扩展 通过View->Show Console菜单打开命令行. 按图操作: 在控制台输入,然后回车: import urllib.request,os; ...

  5. hash表长度优化证明

    hash表冲突的解决方法一般有两个方向: 一个是倾向于空间换时间,使用向量加链表可以最大程度的在节省空间的前提下解决冲突. 另外一个倾向于时间换空间,下面是关于这种思路的一种合适表长度的证明过程: 这 ...

  6. React使用antd Table生成层级多选组件

    一.需求 用户对不同的应用需要有不同的权限,用户一般和角色关联在一起,新建角色的时候会选择该角色对应的应用,然后对应用分配权限.于是写了一种实现的方式.首先应用是一个二级树,一级表示的是应用分组,二级 ...

  7. 这些.NET开源项目你知道吗?.NET平台开源文档与报表处理组件集合(三)

    在前2篇文章这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧 和这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,大伙热情高涨.再次拿出自己的私货,在.NET平台 ...

  8. SQL Server-聚焦APPLY运算符(二十七)

    前言 其实有些新的特性在SQL Server早就已经出现过,但是若非系统的去学习数据库你会发现在实际项目中别人的SQL其实是比较复杂的,其实利用新的SQL Server语法会更加方便和简洁,从本节开始 ...

  9. 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)

    本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...

  10. spring源码分析之<context:property-placeholder/>和<property-override/>

    在一个spring xml配置文件中,NamespaceHandler是DefaultBeanDefinitionDocumentReader用来处理自定义命名空间的基础接口.其层次结构如下: < ...