Entity Framework 6 Recipes 2nd Edition(9-7)译-在WCF服务中序列化代理
9-7. 在WCF服务中序列化代理
问题
从一个查询里返回一个动态代理对象,想要把它序列为一个POCO(Plain-Old CLR Objects)对象.
实现基于POCO实体对象, 在运行时,EF会为每个实体自动生成一个派生类型,被称为动态代理对象,
代理对象会为POCO类重载很多虚拟属性来注入执行操作的挂钩,像变更跟踪,和延迟加载关联的实体。
解决方案
假设我们有一个如Figure 9-7.所示的客户模型
Figure 9-7. 客户模型
我们将使用ProxyDataContractResolver类在服务端把一个代理对象反序列化为Client的POCO类
1. 创建Wcf服务应用程序.添加一个ADO.NET实体数据模型,并选择”Client”表,创建好的模型,就如 Figure 9-7.所示.
2.打开Client的 POCO类, 为每个属性添加virtual关键字,如Listing 9-33所示 . 这样EF就可以创建动态代理类了。
============================================================================================
■■注意:如果你修改EDMX文件,EF会自动重新生成类,会重写第2步里你对类的修改,你可以再次修改类或是修改T4模板来生成实体代码。
=======================================================================
Listing 9-33. Our Client POCO Class and Our Object Vontext
public partial class Client
{
public virtual int ClientId { get; set; }
public virtual string Name { get; set; }
public virtual string Email { get; set; }
}
3.我们需要为DataContractSerializer使用ProxyDataContractResolver类为WCF服务的客户端把client 代理转换为client实例.为此我们将创建一个操作行为特性 ,并且让GetClient() 方法使用这个特性。新特性的代码如 Listing 9-34 所示.注意:ProxyDataContractResolver 类属于EF命名System.Data.Entity.Core.Objects
Listing 9-34. Our Custom Operation Behavior Attribute
namespace Recipe7
{
public class ApplyProxyDataContractResolverAttribute :
Attribute, IOperationBehavior
{
public void AddBindingParameters(OperationDescription description,
BindingParameterCollection parameters)
{
}
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
dataContractSerializerOperationBehavior.DataContractResolver =
new ProxyDataContractResolver();
}
public void Validate(OperationDescription description)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
DataContractSerializerOperationBehavior
dataContractSerializerOperationBehavior =
operationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();
dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver();
}
}
}
4.用Listing 9-35里的代码修改IService1.cs 接口
Listing 9-35. Our IService1 Interface Definition, Which Replaces the Code in IService1.cs
[ServiceContract]
public interface IService1
{
[OperationContract]
void InsertTestRecord();
[OperationContract]
Client GetClient();
[OperationContract]
void Update(Client client);
}
5. 用Listing 9-36里的代码修改Service1.svc.cs 文件来实现服务接口。
Listing 9-36. The Implementation of the IService1 Interface, Which Replaces the Code in IService1.svc.cs
public class Service1 : IService1
{
public void InsertTestRecord()
{
using (var context = new EFRecipesEntities())
{
//删除之前的测试数据
context.Database.ExecuteSqlCommand("delete from chapter9.client");
//插入新的测试数据
context.Database.ExecuteSqlCommand(@"insert into chapter9.client(name,email)values('Jerry Jones','jjones@gmial.com')");
}
}
[ApplyProxyDataContractResolver]
public Client GetClient()
{
using (var context = new EFRecipesEntities())
{
context.Configuration.LazyLoadingEnabled = false;
return context.Clients.Single();
}
}
public void Update(Client client)
{
using (var context = new EFRecipesEntities())
{
context.Entry(client).State = EntityState.Modified;
context.SaveChanges();
}
}
}
6.在解决方案中添加一个新的Windows控制台应用程序,这是我们用来测试的客户端,代码如
Listing 9-37所示,添加WCF的引用。
Listing 9-37. Our Windows console application test client
class Program
{
static void Main(string[] args)
{
using (var serviceClient=new ServiceReference1.Service1Client())
{
serviceClient.InsertTestRecord();
var client = serviceClient.GetClient();
Console.WriteLine("Client is :{0} at {1}",client.Name,client.Email);
client.Name = "Alex Park";
client.Email = "AlexP@hotmail.com";
serviceClient.Update(client);
client = serviceClient.GetClient();
Console.WriteLine("Client changed to: {0} at {1}",client.Name, client.Email);
Console.WriteLine("\npress any key to exit...");
Console.ReadKey(true);
}
}
}
以下是控制台输出结果:
===================================================================
Client is: Jerry Jones at jjones@gmail.com
Client changed to: Alex Park at AlexP@hotmail.com
=================================================================================
它是如何工作的?
微软建议为WCF使用POCO对象,方便序列化实体对象。如果我们的应用程序使用POCO对象,并支持变更通知(把属性设为virtual and导航对象集合类型为ICollection), EF会为从查询返回的实体创建动态代理。这里有两个关于动态代理和WCF的问题,第一个问题是:必须序列化代理。 而DataContractSerializer 只能序列化和反序列化已知的类型,例如我们例子中的Client实体.然而 EF为Client 实体自动生成一个动态代理类,我们需要序列化这个代理类, 而不是 Client类,DataContractResolver就是解决这个问题的. 它能在序列化期间把一个类型映射到另一个类型. ProxyDataContractResolver 来源于DataContractResolver 并映射代理类型到 POCO类, 例如我们的 Client 实体. 为了使用ProxyDataContractResolver, 我们创建特性 (见 Listing 9-34) 来解决代理转换成POCO类.我们在GetClient()方法上应用这个特性 (见Listing 9-36). 这样Client实体的动态代理能正确的序列化,并被GetClient() 返回给WCF服务的调用者。第二个问题:必须处理延迟加载的问题.当 DataContractSerializer 序列化实体时, 它访问实体的每个属性,这会触发延迟加载导航属性. 这当然不是我们所希望的,所以我们要关闭延迟加载,如Listing 9-36所示。
附:创建示例用到的数据库的脚本文件
转载于:https://www.cnblogs.com/kid1412/p/5143585.html
Entity Framework 6 Recipes 2nd Edition(9-7)译-在WCF服务中序列化代理相关推荐
- Entity Framework 6 Recipes 2nd Edition(9-1)译-用Web Api更新单独分离的实体
第九章 在N层结构的应用程序中使用EF 不是所有的应用都能完全地写入到一个单个的过程中(就是驻留在一个单一的物理层中),实际上,在当今不断发展的网络世界,大量的应用程序的结构包含经典的表现层,应用程, ...
- Entity Framework 6 Recipes 2nd Edition(13-2)译 - 用实体键获取一个单独的实体
问题 不管你用DBFirst,ModelFirst或是CodeFirst的方式,你想用实体键获取一个单独的实体.在本例中,我们用CodeFirst的方式. 解决方案 假设你有一个模型表示一个Paint ...
- Entity Framework 6 Recipes 2nd Edition(13-4)译 - 有效地创建一个搜索查询
问题 你想用LINQ写一个搜索查询,能被转换成更有效率的SQL.另外,你想用EF的CodeFirst方式实现. 解决方案 假设你有如下Figure 13-6所示的模型 Figure 13-6. A s ...
- Entity Framework 6 Recipes 2nd Edition(9-2)译-用WCF更新单独分离的实体
9-2. 用WCF更新单独分离的实体 问题 你想通过WCF为一个数据存储发布查询,插入,删除和修改,并且使这些操作尽可能地简单 此外,你想通过Code First方式实现EF6的数据访问管理 解决方案 ...
- Entity Framework 6 Recipes 2nd Edition(10-6)译 - TPT继承模型中使用存储过程
10-6. TPT继承模型中使用存储过程 问题 想在一个TPT继承模型中使用存储过程 解决方案 假设已有如Figure 10-6所示模型. 在模型里, Magazine(杂志) and DVD继承于基 ...
- Entity Framework 6 Recipes 2nd Edition(12-1)译 - 当SaveChanges( ) 被调用时执行你的代码...
第12章定制EF 在本章的小节里,定制实体对象和EF处理的一些功能.这些小节将涵盖很多"幕后"的事情,能让你的代码更加统一解决一些事情,比如用一个业务规则中心统一地为实体执行验证. ...
- Entity Framework 6 Recipes 2nd Edition(10-5)译 - 在存储模型中使用自定义函数
10-5. 在存储模型中使用自定义函数 问题 想在模型中使用自定义函数,而不是存储过程. 解决方案 假设我们数据库里有成员(members)和他们已经发送的信息(messages) 关系数据表,如Fi ...
- Entity Framework 6 Recipes 2nd Edition(10-3)译 - 返回结果是一个标量值
10-3. 返回结果是一个标量值 问题 想取得存储过程返回的一个标量值. 解决方案 假设我们有如Figure 10-2所示的ATM机和ATM机取款记录的模型 Figure 10-2. 一个ATM机和A ...
- Entity Framework 6 Recipes 2nd Edition(11-5)译 - 从”模型定义”函数返回一个匿名类型...
11-5. 从"模型定义"函数返回一个匿名类型 问题 想创建一个返回一个匿名类型的"模型定义"函数 解决方案 假设已有游客(Visitor) 预订(reserv ...
最新文章
- linux系统关于ping的命令,详解Linux系统中ping和arping命令的用法
- 相机模型--A Theory of Catadioptric Image Formation
- 互联网产品各阶段的标准流程文档
- 3.Ubuntu18.04取消警告音
- VC6生成和调用lib
- 144显示器只有60_HKC IG27电竞显示器体验:27英寸+IPS+144Hz,千元平民价值不值?...
- Spring的OncePerRequestFilter的作用
- 4.事务提交过程,事务基本概念,Oracle中的事务生命周期,保存点savepoint,数据库的隔离级别
- 如何将ListT转换相应的Html(xsl动态转换)(一)
- java 装饰器_JAVA装饰器模式
- 【java】动态高并发时为什么推荐重入锁而不是Synchronized?
- 写给初学者的话---linux使用说明
- 写在2013年最后一天
- WCF服务部署到IIS上,然后通过web服务引用方式出现错误的解决办法
- 并发编程-基础概念介绍
- EMOS批量创建用户邮箱
- paip.代码生成器数据源格式最佳实践
- 保障电邮EMAIL通讯的安全性
- 台式计算机usb口不能用,电脑usb接口没反应是什么原因?电脑usb接口没反应解决方法...
- 微信公众号12大互动技巧