简体   繁体   English

在WCF服务上公开实体框架

[英]Exposing Entity Framework over WCF Service

I need some help here! 我需要一些帮助! I'm trying to create my first application using Entity Framework, WCF, MVVM and WPF technologies. 我正在尝试使用Entity Framework,WCF,MVVM和WPF技术创建我的第一个应用程序。 I'm new to all of them. 我是所有人的新手。 So I create a model for my database using Entity Framework. 所以我使用Entity Framework为我的数据库创建了一个模型。 Then I create my WCF service class. 然后我创建我的WCF服务类。 I have read close to 50 articles about EF and WCF services and I'm all about confusion right now. 我已经阅读了近50篇关于EF和WCF服务的文章,我现在都在混淆。 I know that I'm not supposed to expose my model directly. 我知道我不应该直接暴露我的模型。 Currently I'm using this code as service contract: 目前我正在使用此代码作为服务合同:

namespace Ohmio.DataService
{
    [ServiceContract]

    public class OhmioService
    {
        [OperationContract]
        public IEnumerable<vw_Pedidos> 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<vw_Pedidos> Pedidos = context.CreateQuery<vw_Pedidos>(sqlString);                
                var result = Pedidos.ToList();
                result.ForEach(e => context.Detach(e));
                return result;
            }
        }

        [OperationContract]
        public IEnumerable<Clientes> GetClientes()
        {
            using (var context = new OhmioTestNet())
            {
                var result = context.Clientes.Where(f => f.Activo == true).ToList();
                result.ForEach(e => context.Detach(e));
                return result;
            }
        }
    }
}

My questions: 我的问题:

  1. The problem with it is that don't suppose to expose my data model directly, right? 它的问题是不要直接暴露我的数据模型,对吧? So here I'm returning detached entity of class vw_Pedidos . 所以我在这里返回类vw_Pedidos分离实体。 Is this a bad practice? 这是一种不好的做法吗?

  2. I have read a lot about DTO's and POCO's object, which should I use instead of the above code? 我已经阅读了很多关于DTO和POCO的对象,我应该使用哪个而不是上面的代码?

  3. If I use DTO or POCO to transfer over WCF, do I have to manually create a DTO for each database object? 如果我使用DTO或POCO通过WCF进行传输,是否必须为每个数据库对象手动创建DTO? Do I have to manually create all the properties (fields) for each DB object? 我是否必须手动为每个数据库对象创建所有属性(字段)?

  4. If I add a new field to a database object and need to show it on client, do I have to update my EF model, add the new field manually to the DTO or POCO object? 如果我向数据库对象添加一个新字段并需要在客户端上显示它,我是否必须更新我的EF模型,手动将新字段添加到DTO或POCO对象? This sounds like a maintenance nightmare! 这听起来像是一场维护噩梦!

  5. Is using EntitiesToDTOs a good option for automatic create DTOs based on EF objects? 使用EntitiesToDTOs是基于EF对象自动创建DTO的好选择吗?

  6. Can I use DTO to update data back to database? 我可以使用DTO将数据更新回数据库吗?

Sorry for the multiple questions. 抱歉,有多个问题。 Please help me out here! 请帮帮我吧! I'm searching for a pattern that lead me to an easy to maintain, concern separated code. 我正在寻找一种模式,使我易于维护,关注分离代码。 Thanks! 谢谢!

UPDATE UPDATE

Following TomTom suggestions, i read a lot about POCOs, EF and Linq to Entities. 根据TomTom的建议,我读了很多关于POCO,EF和Linq to Entities的内容。 After that i re-write my whole app. 之后我重写了我的整个应用程序。 I divide my code on 5 projects: 我将我的代码划分为5个项目:

1)DataLayer 1)数据层

2)ModelLayer 2)ModelLayer

3)BusinessLyer 3)BusinessLyer

4)WCF Service Layer 4)WCF服务层

5)WPF Client 5)WPF客户端

For comunications on layers 1 to 5 I use POCO classes mapped to Entity Framework using POCO T4 Template. 对于第1层到第5层的通信,我使用POCO T4模板映射到实体框架的POCO类。 To comunicate layer 4 and 5 over WCF I want to use a custom class to hide some field from client (I don't want to expose the whole POCO class) so I re-write filter function using linq to entities and projection to IEnumerable: 为了通过WCF通信第4层和第5层,我想使用自定义类来隐藏客户端的某些字段(我不想公开整个POCO类)所以我使用linq重写了过滤函数到实体并投影到IEnumerable:

public IEnumerable<PedidosList> Pedidos_Listar(string sComprobante, Clientes MyCliente = null, DateTime? dDesde = null, DateTime? dHasta = null, bool bCumplidos = false)
            {           
                using (var context = new OhmioEntities())
                {
                    IEnumerable<PedidosList> 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 <= dHasta);
                    if (bCumplidos == false) query = query.Where(i => i.Entregado == false);                
                    return query.ToList();
                }
            }

Is this the best way to do this? 这是最好的方法吗? Can i make the projection AFTER the filter? 我可以在滤镜后进行投影吗? Thanks! 谢谢!

The problem with it is that don't suppose to expose my data model directly, right? 它的问题是不要直接暴露我的数据模型,对吧? So here i'm returning dettached entity of class vw_Pedidos. 所以在这里我将返回类vw_Pedidos的脱离实体。 Is this a bad practice? 这是一种不好的做法吗?

Yes. 是。

I have read a lot about DTO's and POCO's object, wich should i use instead of the above code? 我已经阅读了很多关于DTO和POCO的对象,我应该使用哪个而不是上面的代码?

Both. 都。 Given that a DTO pretty much normally is a POCO. 鉴于DTO通常是POCO。 Maybe you try to understand what the words MEAN. 也许你试着理解MEAN这几个字。 POCO is a "Plain Old C# Object" (not required to inherit from a base class) and that is totally normal for a POCO. POCO是一个“普通的旧C#对象”(不需要从基类继承),这对于POCO来说是完全正常的。

If I use DTO or POCO to transfer over WCF, do i have to manualy create a DTO for each Database Object? 如果我使用DTO或POCO通过WCF进行传输,我是否必须为每个数据库对象手动创建DTO? Do I have manualy create all the properties (Fields) for each DB object? 我是否为每个数据库对象创建了所有属性(字段)?

No. Ever heard of T4? 没有听说过T4? That can be scripted. 这可以编写脚本。 That said, these normally aren't database but API objects - the WCF service is a (public) front end of the server program. 也就是说,这些通常不是数据库而是API对象--WCF服务是服务器程序的(公共)前端。

If i add a new field to a DB object and need to show it on client, do i have to update my EF model, add the new field manualy to DTO or POCO object? 如果我向DB对象添加一个新字段并需要在客户端上显示它,我是否必须更新我的EF模型,将新字段手动添加到DTO或POCO对象? This sounds like a mantenance nigthmare! 这听起来像一个维护的nigthmare!

It absolutely is one. 绝对是一个。 If you do things without thinking. 如果你不假思索地做事。 Seriously, once you have hammered out the basic model, this is not something that happens every 15 minutes. 说真的,一旦你敲定了基本模型,这不是每15分钟发生一次的事情。 Also it includes a significant work on the front end and logic anyway - I mean, if the property is useless then hey, why put it in? 它还包括前端和逻辑方面的重要工作 - 我的意思是,如果属性没用,那么嘿,为什么要把它放进去? If it is not useless it is a lot of work anyway. 如果它没用,那么无论如何都要做很多工作。 And the models can be updated, not need to regenerate. 并且模型可以更新,而不需要重新生成。

Heck, I normally work with non-trivial databases. 哎呀,我通常使用非平凡的数据库。 In this case a change is not "regenerate a model", it also includes "write a sql update script for versioning" and "test the update performance" (adding a field to a multi-billion row table with default value and generating indices can take some time). 在这种情况下,更改不是“重新生成模型”,它还包括“编写用于版本控制的sql更新脚本”和“测试更新性能”(将字段添加到具有默认值的数十亿行表并生成索引可以需要一些时间)。 And it still is no nightmare because this does not happen every 5 minutes. 它仍然不是噩梦,因为这不会每5分钟发生一次。 MOST stuff is not "add fields", it is "Program". MOST的东西不是“添加字段”,而是“程序”。

Can i use DTO to update data back to database? 我可以使用DTO将数据更新回数据库吗?

What else? 还有什么?

Please help me out here! 请帮帮我吧! I'm searching for a pattern that lead me to an easy to mantain, concern separated code 我正在寻找一种模式,让我很容易保持,关注分开的代码

You will not find one. 你找不到一个。 This is a matter of making the right compromise. 这是做出正确妥协的问题。 You DO seem to overestimate the amount of changes that happen in a project though. 您似乎高估了项目中发生的变化量。

You do more well to assume that the WCF service is a trust boundary and public API - much like a website, just for consumption by a computer. 您可以更好地假设WCF服务是信任边界和公共API - 非常类似于网站,仅供计算机使用。 The objects you expose there must not absolutely conform to the database internals. 您在那里公开的对象必须绝对不符合数据库内部。 It is better to generate them separately and possibly change them to be more in line with what is needed for the public API - than to expose back-end implementation details to an API. 最好单独生成它们并可能将它们更改为更符合公共API所需的内容 - 而不是将后端实现细节公开给API。

I have to say, though, your work is made a lot more complicated by the archaic and absolutely contra-productive way you access the database - start using a proper sql generator and object mapper, or you'll have a maintenance nightmare right there, regardless how you do the rest. 但是,我不得不说,通过访问数据库的古老且绝对相反的方式使你的工作变得更加复杂 - 开始使用正确的sql生成器和对象映射器,或者你将在那里进行维护噩梦,不管你怎么做其余的事。 Putting together SQL strings like that is a SERIOUS "no, never". 将这样的SQL字符串放在一起是一个严重的“不,永远”。 And look up how to expose OData via WCF. 并查看如何通过WCF公开OData。 That gives you query functionality via URLs. 这为您提供了通过URL查询功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM