5

I need some help here! I'm trying to create my first application using Entity Framework, WCF, MVVM and WPF technologies. I'm new to all of them. So I create a model for my database using Entity Framework. Then I create my WCF service class. I have read close to 50 articles about EF and WCF services and I'm all about confusion right now. 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. 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?

  3. If I use DTO or POCO to transfer over WCF, do I have to manually create a DTO for each database object? 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? This sounds like a maintenance nightmare!

  5. Is using EntitiesToDTOs a good option for automatic create DTOs based on EF objects?

  6. Can I use DTO to update data back to database?

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

Following TomTom suggestions, i read a lot about POCOs, EF and Linq to Entities. After that i re-write my whole app. I divide my code on 5 projects:

1)DataLayer

2)ModelLayer

3)BusinessLyer

4)WCF Service Layer

5)WPF Client

For comunications on layers 1 to 5 I use POCO classes mapped to Entity Framework using POCO T4 Template. 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:

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!

ericpap
  • 2,917
  • 5
  • 33
  • 52
  • Big subject ;) Not an answer as such but i would start here with this http://www.codeproject.com/Articles/537161/Implementing-a-WCF-Service-with-Entity-Framework-v it explains WCF with Entity Framework very nicely before you move onto MVVM part – SWilko Mar 18 '14 at 15:35
  • Thanks for the answer! I already read this article and thats exactly my point. In this article a DataContract class is created to Access the Product EF object and then all the field are manualy mapped one by one between datacontract class and EF class! This sounds like crazy! In fact you have 2 clases with same property that you need to manualy update! It's a mantenance nigthmare! Isnt it a better way to do this? – ericpap Mar 18 '14 at 15:41
  • Your update looks fine (though you do the same if and filter check twice in a row, probably just a typo). I would personally do any filtering first, so you don't waste CPU time creating objects you are going to just throw away, but its only a small optimization. – BradleyDotNET Mar 28 '14 at 16:10
  • The article mentioned by @dellywheel in the first comment is gone. An older version of it is at http://www.codeproject.com/Articles/127395/Implementing-a-WCF-Service-with-Entity-Framework . The author of the article also has a book https://www.packtpub.com/application-development/wcf-multi-layer-services-development-entity-framework-4th-edition – Walter Stabosz Jan 09 '15 at 03:09

1 Answers1

15

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. 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?

Both. Given that a DTO pretty much normally is a POCO. Maybe you try to understand what the words MEAN. POCO is a "Plain Old C# Object" (not required to inherit from a base class) and that is totally normal for a POCO.

If I use DTO or POCO to transfer over WCF, do i have to manualy create a DTO for each Database Object? Do I have manualy create all the properties (Fields) for each DB object?

No. Ever heard of 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.

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? This sounds like a mantenance 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. 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). And it still is no nightmare because this does not happen every 5 minutes. MOST stuff is not "add fields", it is "Program".

Can i use DTO to update data back to database?

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. 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.

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. Putting together SQL strings like that is a SERIOUS "no, never". And look up how to expose OData via WCF. That gives you query functionality via URLs.

Gustav Bertram
  • 14,591
  • 3
  • 40
  • 65
TomTom
  • 61,059
  • 10
  • 88
  • 148
  • Thanks for your answer TomTom. So i perfectly understand and agree with you that the data exposed by my service will be different from the one DataLayer get from the DB, so it's a bad idea to directly expose my EF object. I suppose one option will be to create a datacontract DTO class and manualy map only the fields that i want to expose in the way i wanted to be exposed, right? Also i need some clarification with the last part of your answer. Why you say my filter code is "archaric and absolutly contraproductive"? Please is there a better way of filter data with optional aditive filters?Thks – ericpap Mar 18 '14 at 16:01
  • I would actually look into an LINQ Integrated projection ;) Re archaric - the example code is manually constructing SQL via string manipulation. THat is archaic. Linq can do that nicely (IQueryable can have multiple where clauses) and you can expose an IQueryable directly via WCF. http://stackoverflow.com/questions/4291370/expose-iqueryable-over-wcf-service – TomTom Mar 18 '14 at 16:05
  • Thanks TomTom for the answer. I'm sure that your response is technicaly outstanding but beeing a newbie there some things i don't understand. You clarify to me what i shouldn't do: I'm not suposed to expose my EF object. But what do i do then? How do i expose data on WCF service? Should I create DTO (Or POCO's) and manualy map fields? I saw the think about LINQ and IQueryable DTO, but in there talks about client filtering data. Is that the case? In this case i expose my entire table and filter on client? Sorry for my ignorance. – ericpap Mar 18 '14 at 16:43
  • Client filtering means that the client can send the filter to the server - and tha gets put into SQL. I am sorry to be blunt, but that is not something I Can all explain here in a comment or even a question - it is time to read the API and work throug the examplkes being there. I would use POCO DTO (again: a DTO normally IS a POCO) that are projected from LINQ queries and exposed as IQueryable preferably on an ODATA compatible WCF endpoint. Lots of keywords for you to start learning. – TomTom Mar 18 '14 at 16:56
  • Ok TomTom thank you for that. I wasn't asking you to wright my query just to point me in rigth direction, a more of "do this" instead or "don't do that". I will look up all that you suggest. About LINQ I supose i should search for Linq to Entities since i'm using EF, rigth? Thank you again. – ericpap Mar 18 '14 at 17:41