《Entity Framework 6 Recipes》中文翻译——第九章EntityFramework在N层架构程序中的应用(七)
在WCF服务中的序列化代理
问题
您有一个从查询返回的动态代理对象,你想要把它像POCO对象已经进行序列化。在序列化基于实体对象的POCO(普通旧CLR对象)时,实体框架会自动生成一个动态生成的派生类型为每个POCO实体对象,称为动态代理对象。代理对象覆盖了许多的POCO类虚拟属性去注册钩子为展现功能,如更改跟踪和相关实体的延迟加载。
解决方案
假设你有如下一个模型
我们将使用代理数据契约解析器反序列化一个代理对象为POCO对象在WCF客户端。执行以下操作:
1、创建一个新的WCF服务应用程序。添加ADO.NET Entity Data Model,选择Client表
2、打开实体框架生成的客户端POCO类,并添加虚拟关键字为每个属性,这样做会导致实体框架生成动态代理类。
public class Client { public virtual int ClientId { get; set; } public virtual string Name { get; set; } public virtual string Email { get; set; } }
我们需要的数据协定序列化程序使用代理数据契约解析类为WCF服务的客户端将客户端Client代理转换为Client实体。为此,我们将创建一个操作行为属性和应用属性到GetClient()服务方法。记住,代理数据契约解析类驻留在实体框架命名空间。
public class ApplyProxyDataContractResolverAttribute : Attribute, IOperationBehavior { public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = operationDescription.Behaviors.Find <DataContractSerializerOperationBehavior>(); dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver(); } public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) { DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = operationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>(); dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver(); } public void Validate(OperationDescription operationDescription) { } }
4、修改Iservice.cs的代码如下
[ServiceContract] public interface IService1 { [OperationContract] void InsertTestRecord(); [OperationContract] Client GetClient(); [OperationContract] void Update(Client client); }
5、实现Iservice中的接口在IService1.svc.cs 中
public class Service1 : IService1 { [ApplyProxyDataContractResolverAttribute] public Client GetClient() { using (var context = new EntitiesContext()) { context.Configuration.LazyLoadingEnabled = false; return context.Clients.Single(); } } [ApplyProxyDataContractResolverAttribute] public void InsertTestRecord() { using (var context = new EntitiesContext()) { context.Database.ExecuteSqlCommand("delete from Client"); context.Database.ExecuteSqlCommand(@"insert into Client(Name, Email) values ('Jerry Jones','jjones@gmail.com')"); } } [ApplyProxyDataContractResolverAttribute] public void Update(Client client) { using (var context = new EntitiesContext()) { context.Entry(client).State = EntityState.Modified; context.SaveChanges(); } } }
6、在解决方案中添加一个新的控制台应用程序项目作为我们的客户端,同时添加WCF服务引用
class Program { static void Main(string[] args) { using (var serviceClient = new Service1Client()) { serviceClient.InsertTestRecord(); var client = serviceClient.GetClient(); Console.WriteLine("Client is: {0} at {1}", client.Name, client.Email); client.Name = "Alex Park"; client.Email = "Alex P@hotmail.com"; serviceClient.Update(client); client = serviceClient.GetClient(); Console.WriteLine("Client changed to: {0} at {1}", client.Name, client.Email); } } }
结果:
微软建议使用WCF POCO对象简化实体对象的序列化。然而,如果你的应用程序是使用POCO对象改变的通知(你有虚拟和显著的性能导航属性集合的类型是ICollection),然后实体框架会创建查询返回的实体动态代理。