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:
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?I have read a lot about DTO's and POCO's object, which should I use instead of the above code?
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?
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!
Is using EntitiesToDTOs a good option for automatic create DTOs based on EF objects?
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!