在WCF服务上公开entity framework

我需要一些帮助! 我正在尝试使用Entity Framework,WCF,MVVM和WPF技术创建我的第一个应用程序。 我是所有人的新手。 所以我使用Entity Framework为我的数据库创建了一个模型。 然后我创建我的WCF服务类。 我已经阅读了近50篇关于EF和WCF服务的文章,我现在都在混淆。 我知道我不应该直接暴露我的模型。 目前我正在使用此代码作为服务合同:

namespace Ohmio.DataService { [ServiceContract] public class OhmioService { [OperationContract] public IEnumerable ListarPedidos(string IDComprobante, bool bEntregados, int Numero = -1, int IDCliente = -1) { using (var context = new OhmioTestNet()) { string sqlString="SELECT VALUE cs FROM OhmioTestNet.vw_Pedidos AS cs WHERE cs.ID_Comprobante=='" + IDComprobante + "' AND "; if (Numero != -1) sqlString += "cs.Numero=="+ Numero.ToString() +" AND "; if (IDCliente != -1) sqlString += "cs.ID_Cliente=="+ IDCliente.ToString()+" AND "; if (!bEntregados) sqlString += "cs.Entregado==false AND "; sqlString =sqlString.Substring(0,sqlString.Length-4); ObjectQuery Pedidos = context.CreateQuery(sqlString); var result = Pedidos.ToList(); result.ForEach(e => context.Detach(e)); return result; } } [OperationContract] public IEnumerable GetClientes() { using (var context = new OhmioTestNet()) { var result = context.Clientes.Where(f => f.Activo == true).ToList(); result.ForEach(e => context.Detach(e)); return result; } } } } 

我的问题:

  1. 它的问题是不要直接暴露我的数据模型,对吧? 所以我在这里返回类vw_Pedidos分离实体。 这是一个不好的做法吗?

  2. 我已经阅读了很多关于DTO和POCO的对象,我应该使用哪个而不是上面的代码?

  3. 如果我使用DTO或POCO通过WCF进行传输,是否必须为每个数据库对象手动创建DTO? 我是否必须手动为每个数据库对象创建所有属性(字段)?

  4. 如果我向数据库对象添加一个新字段并需要在客户端上显示它,我是否必须更新我的EF模型,手动将新字段添加到DTO或POCO对象? 这听起来像是一场维护噩梦!

  5. 使用EntitiesToDTOs是基于EF对象自动创建DTO的好选择吗?

  6. 我可以使用DTO将数据更新回数据库吗?

抱歉,有多个问题。 请帮帮我吧! 我正在寻找一种模式,使我易于维护,关注分离代码。 谢谢!

UPDATE

根据TomTom的建议,我读了很多关于POCO,EF和Linq to Entities的内容。 之后我重写了我的整个应用程序。 我将我的代码划分为5个项目:

1)数据层

2)ModelLayer

3)BusinessLyer

4)WCF服务层

5)WPF客户端

对于第1层到第5层的通信,我使用POCO T4模板映射到entity framework的POCO类。 为了通过WCF通信第4层和第5层,我想使用自定义类来隐藏客户端的某些字段(我不想公开整个POCO类)所以我使用linq重写了过滤函数到实体并投影到IEnumerable:

 public IEnumerable Pedidos_Listar(string sComprobante, Clientes MyCliente = null, DateTime? dDesde = null, DateTime? dHasta = null, bool bCumplidos = false) { using (var context = new OhmioEntities()) { IEnumerable query = from Pedidos in context.Pedidos join Clientes in context.Clientes on Pedidos.ID_Cliente equals Clientes.ID_Cliente where Pedidos.ID_Comprobante == sComprobante select new PedidosList {ID_Pedido = Pedidos.ID_Pedido, Fecha=Pedidos.Fecha, Aprobado=Pedidos.Aprobado, Bruto=Pedidos.Bruto, Cliente=Clientes.RazonFantasia, FechaEntrega=Pedidos.FechaEntrega, Neto=Pedidos.Neto, Numero=Pedidos.Numero, Observaciones=Pedidos.Observaciones, Entregado=Pedidos.Entregado, ID_Cliente=Pedidos.ID_Cliente }; if (MyCliente != null) query = query.Where(i => i.ID_Cliente == MyCliente.ID_Cliente); if (MyCliente != null) query = query.Where(i => i.ID_Cliente == MyCliente.ID_Cliente); if (dDesde != null && dHasta != null) query = query.Where(i => i.Fecha >= dDesde && i.Fecha  i.Entregado == false); return query.ToList(); } } 

这是最好的方法吗? 我可以在滤镜后进行投影吗? 谢谢!

它的问题是不要直接暴露我的数据模型,对吧? 所以我在这里返回类vw_Pedidos的脱离实体。 这是一个不好的做法吗?

是。

我已经阅读了很多关于DTO和POCO的对象,我应该使用哪个而不是上面的代码?

都。 鉴于DTO通常是POCO。 也许你试着理解MEAN这两个词。 POCO是一个“普通的旧C#对象”(不需要从基类inheritance),这对于POCO来说是完全正常的。

如果我使用DTO或POCO通过WCF进行传输,我是否必须为每个数据库对象手动创建DTO? 我是否手动为每个数据库对象创建了所有属性(字段)?

没有听说过T4? 这可以编写脚本。 也就是说,这些通常不是数据库而是API对象–WCF服务是服务器程序的(公共)前端。

如果我向DB对象添加一个新字段并需要在客户端上显示它,我是否必须更新我的EF模型,将新字段手动添加到DTO或POCO对象? 这听起来像是一种维持的噩梦!

绝对是一个。 如果你不假思索地做事。 说真的,一旦你敲定了基本模型,这不是每15分钟发生一次的事情。 它还包括前端和逻辑方面的重要工作 – 我的意思是,如果财产没用,那么嘿,为什么要把它放进去? 如果它没有用,那么无论如何都要做很多工作。 并且模型可以更新,不需要重新生成。

哎呀,我通常使用非平凡的数据库。 在这种情况下,更改不是“重新生成模型”,它还包括“编写用于版本控制的sql更新脚本”和“测试更新性能”(将字段添加到具有默认值的数十亿行表并生成索引可以需要一些时间)。 它仍然不是噩梦,因为这不会每5分钟发生一次。 MOST的东西不是“添加字段”,而是“程序”。

我可以使用DTO将数据更新回数据库吗?

还有什么?

请帮帮我吧! 我正在寻找一种模式,这种模式让我很容易保持原状,关注分开的代码

你找不到一个。 这是做出正确妥协的问题。 您似乎高估了项目中发生的变化量。

您可以更好地假设WCF服务是信任边界和公共API – 非常类似于网站,仅供计算机使用。 您在那里公开的对象必须绝对不符合数据库内部。 最好单独生成它们并可能将它们更改为更符合公共API所需的内容 – 而不是将后端实现细节公开给API。

但是,我不得不说,你的工作因为访问数据库的过时和绝对反应方式而变得更加复杂 – 开始使用正确的sql生成器和对象映射器,或者你将在那里进行维护噩梦,不管你怎么做其余的事。 将这样的SQL字符串放在一起是一个严重的“不,永远”。 并查看如何通过WCF公开OData。 这为您提供了通过URL查询function。