2012-04-03 19 views
5

Utilizando WCF Data Services (y el último Entity Framework), deseo devolver datos de un procedimiento almacenado. Los campos sproc devueltos no coinciden 1: 1 cualquier entidad en mi db, por lo que crean un nuevo tipo de complejo para que en el modelo edmx (en lugar de adjuntar una entidad existente):¿Cómo consumir un objeto complejo desde un sproc utilizando WCF Data Services/OData?

  1. Haga clic con el *. modelo edmx/Añadir/función de importación
  2. Seleccione la sproc (devuelve tres campos) - GetData
  3. clic en Obtener información columna
  4. Agregue el Nombre de la función de importación: GetData
  5. Haga clic en Crear nuevo tipo de complejo - GetData_Result

En el servicio, que definen:

[WebGet] 
    public List<GetData_Result> GetDataSproc() 
    { 
     PrimaryDBContext context = new PrimaryDBContext(); 
     return context.GetData().ToList(); 
    } 

he creado una aplicación de consola rápida para poner a prueba, y ha añadido una referencia a System.Data.Services y System.Data.Services.Client - esto después de ejecutar Install-Package EntityFramework -Pre, pero las versiones en las bibliotecas son 4.0 y no se 5.x.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data.Services.Client; 
using ConsoleApplication1.PrimaryDBService; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      DataServiceContext context = new DataServiceContext(new Uri("http://localhost:50100/PrimaryDataService1.svc/")); 
      IEnumerable<GetData_Result> result = context.Execute<GetData_Result>(new Uri("http://localhost:50100/PrimaryDataService1.svc/GetDataSproc")); 
      foreach (GetData_Result w in result) 
      { 
       Console.WriteLine(w.ID + "\t" + w.WHO_TYPE_NAME + "\t" + w.CREATED_DATE); 
      } 

      Console.Read(); 
     } 
    } 
} 

no hizo uso de la UriKind.Relative o cualquier otra cosa para complicar esto.

Cuando navego en el navegador hacia la URL, veo datos, pero cuando los consumo en la aplicación de mi consola, no obtengo nada.

Adición de rastreo a la mezcla:

<system.diagnostics> 
    <sources> 
     <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true"> 
     <listeners> 
      <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\temp\WebWCFDataService.svclog" /> 
     </listeners> 
     </source> 
    </sources> 
    </system.diagnostics> 

... y la apertura mediante el seguimiento de servicio Visor de Microsoft, veo dos advertencias: Idential

contexto de evaluación de configuración no se ha encontrado.

<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent"> 
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system"> 
<EventID>524312</EventID> 
<Type>3</Type> 
<SubType Name="Warning">0</SubType> 
<Level>4</Level> 
<TimeCreated SystemTime="2012-04-03T14:50:11.8355955Z" /> 
<Source Name="System.ServiceModel" /> 
<Correlation ActivityID="{66f1a241-2613-43dd-be0c-341149e37d30}" /> 
<Execution ProcessName="WebDev.WebServer40" ProcessID="5176" ThreadID="10" /> 
<Channel /> 
<Computer>MyComputer</Computer> 
</System> 
<ApplicationData> 
<TraceData> 
<DataItem> 
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Warning"> 
<TraceIdentifier>http://msdn.microsoft.com/en-US/library/System.ServiceModel.EvaluationContextNotFound.aspx</TraceIdentifier> 
<Description>Configuration evaluation context not found.</Description> 
<AppDomain>fd28c9cc-1-129779382115645955</AppDomain> 
</TraceRecord> 
</DataItem> 
</TraceData> 
</ApplicationData> 
</E2ETraceEvent> 

Así que ¿por qué estoy capaz de ver los datos desde el navegador, pero no cuando se consume en mi aplicación?

- ACTUALIZACIÓN -

he descargado el Microsoft WCF Data Services October 2011 CTP que expuso DataServiceProtocolVersion.V3, creó un nuevo servidor y el cliente y se hace referencia Microsoft.Data.Services.Client (v4.99.2.0). Ahora conseguir el siguiente error en el cliente cuando se trata iterate en el bucle foreach:

Hay una coincidencia de tipos entre el cliente y el servicio. Tipo 'ConsoleApplication1.WcfDataServiceOctCTP1.GetDataSproc_Result' es un tipo de entidad , pero el tipo en la carga útil de respuesta no representa un tipo de entidad. Asegúrese de que los tipos definidos en el cliente coincidan con el modelo de datos del servicio o actualice la referencia del servicio en el cliente .

Probé lo mismo al hacer referencia a la entidad real - funciona bien, por lo que el mismo problema.

Respuesta

2

Recap: Quiero crear un servicio de WCF de alto rendimiento DAL (capa de acceso a datos) que devuelve procedimientos almacenados fuertemente tipados. Inicialmente utilicé un proyecto de "Servicios de datos de WCF" para lograr esto. Parece que tiene sus limitaciones, y después de revisar performance metrics de diferentes ORM, terminé usando Dapper para el acceso a datos dentro de un servicio básico de WCF.

Primero creé el modelo * .edmx y creé el POCO para mi sproc.

A continuación, creó una base y BaseRepository MiscDataRepository:

namespace WcfDataService.Repositories 
{ 
    public abstract class BaseRepository 
    { 
     protected static void SetIdentity<T>(IDbConnection connection, Action<T> setId) 
     { 
      dynamic identity = connection.Query("SELECT @@IDENTITY AS Id").Single(); 
      T newId = (T)identity.Id; 
      setId(newId); 
     } 

     protected static IDbConnection OpenConnection() 
     { 
      IDbConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["PrimaryDBConnectionString"].ConnectionString); 
      connection.Open(); 
      return connection; 
     } 
    } 
} 

namespace WcfDataService.Repositories 
{ 
    public class MiscDataRepository : BaseRepository 
    { 
     public IEnumerable<GetData_Result> SelectAllData() 
     { 
      using (IDbConnection connection = OpenConnection()) 
      { 
       var theData = connection.Query<GetData_Result>("sprocs_GetData", 
        commandType: CommandType.StoredProcedure); 

       return theData; 
      } 
     } 
    } 
} 

La clase de servicio:

namespace WcfDataService 
{ 
    public class Service1 : IService1 
    { 
     private MiscDataRepository miscDataRepository; 

     public Service1() 
      : this(new MiscDataRepository()) 
     { 
     } 

     public Service1(MiscDataRepository miscDataRepository) 
     { 
      this.miscDataRepository = miscDataRepository; 
     } 

     public IEnumerable<GetData_Result> GetData() 
     { 
      return miscDataRepository.SelectAllData(); 
     } 
    } 
} 

... y luego creó una aplicación de consola sencilla para mostrar los datos:

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Service1Client client = new Service1Client(); 
      IEnumerable<GetData_Result> result = client.GetData(); 
      foreach (GetData_Result d in result) 
      { 
       Console.WriteLine(d.ID + "\t" + d.WHO_TYPE_NAME + "\t" + d.CREATED_DATE); 
      } 
      Console.Read(); 
     } 
    } 
} 

También lo llevé a cabo usando PetaPOCO, que tomó muchos archivos s el tiempo de instalar que Dapper - unas pocas líneas de código:

namespace PetaPocoWcfDataService 
{ 
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together. 
    public class Service1 : IService1 
    { 
     public IEnumerable<GetData_Result> GetData() 
     { 
      var databaseContext = new PetaPoco.Database("PrimaryDBContext"); // using PetaPOCO for data access 
      databaseContext.EnableAutoSelect = false;        // use the sproc to create the select statement 

      return databaseContext.Query<GetData_Result>("exec sproc_GetData"); 
     } 
    } 
} 

me gusta lo rápido y sencillo que era PetaPOCO configuración, pero utilizando el patrón de repositorio con Dapper se escala mucho mejor para un proyecto de empresa.

También era bastante simple crear objetos complejos directamente desde el EDMX, para cualquier procedimiento almacenado, y luego consumirlos.

Por ejemplo, creé un tipo de devolución de tipo complejo llamado ProfileDetailsByID_Result basado en el sproc sq_mobile_profile_get_by_id.

public ProfileDetailsByID_Result GetAllProfileDetailsByID(int profileID) 
{ 
    using (IDbConnection connection = OpenConnection("DatabaseConnectionString")) 
    { 
     try 
     { 
      var profile = connection.Query<ProfileDetailsByID_Result>("sq_mobile_profile_get_by_id", 
       new { profileid = profileID }, 
       commandType: CommandType.StoredProcedure).FirstOrDefault(); 

      return profile; 
     } 
     catch (Exception ex) 
     { 
      ErrorLogging.Instance.Fatal(ex);  // use singleton for logging 
      return null; 
     } 
    } 
} 

Por lo tanto, usar Dapper junto con algunas entidades EDMX parece ser una buena manera rápida de hacer que las cosas funcionen. Puede que me equivoque, pero no estoy seguro de por qué Microsoft no pensó en todo esto: no admite tipos complejos con OData.

--- --- ACTUALIZACIÓN

Así que finalmente me dieron una respuesta de Microsoft, cuando me planteó la cuestión hace más de un mes:

Hemos realizado investigaciones sobre esto y nos han encontrado que la biblioteca del cliente Odata no es compatible con tipos complejos. Por lo tanto, lamento informarle que no hay mucho que podamos hacer para resolverlo.

* Opcional: Para obtener una solución para este problema, debe utilizar un tipo de enfoque Xml a Linq para obtener los tipos complejos.

Muchas gracias por su comprensión en este asunto. Por favor, deje para saber si usted tiene alguna pregunta. Si podemos ser de más ayuda , háganoslo saber.

Saludos,

parece extraño.

Cuestiones relacionadas