2012-04-03 61 views
5

使用WCF數據服務(和最新的實體框架),我想從存儲過程返回數據。返回的sproc字段與1:1的數據庫不匹配,因此我在edmx模型中創建了一個新的複雜類型(而不是附加現有實體):如何使用WCF Data Services/OData從sproc中消耗複雜對象?

  1. 右鍵單擊*。 EDMX模型/添加/函數導入
  2. 選擇存儲過程(返回三個字段) - 的GetData
  3. 單擊獲取列信息
  4. 添加函數導入名稱:的GetData
  5. 單擊創建新的複雜類型 - GetData_Result

在服務上,我定義:

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

我創建了一個快速的控制檯應用程序進行測試,並增加了一個參考System.Data.ServicesSystem.Data.Services.Client - 運行Install-Package EntityFramework -Pre在此之後,但在庫的版本是4.0,而不是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(); 
     } 
    } 
} 

我沒有使用UriKind.Relative或其他任何東西來使這個複雜化。

當我在瀏覽器中導航到URL時,我看到了數據,但是當我在控制檯應用程序中使用它時,我一無所獲。

添加跟蹤進來:

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

...並使用Microsoft服務跟蹤查看器打開,我看到兩個idential警告:

配置評價方面沒有發現。

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

那麼,爲什麼我能夠從瀏覽器中看到的數據,而不是在我的應用程序消耗?

- 更新 -

我下載裏面露出DataServiceProtocolVersion.V3Microsoft WCF Data Services October 2011 CTP,創造了一個新的主機和客戶端和參考Microsoft.Data.Services.Client(v4.99.2.0)。

還有就是客戶端和服務之間的類型不匹配:現在在foreach循環迭代試圖獲取時,在客戶端上下面的錯誤。類型 'ConsoleApplication1.WcfDataServiceOctCTP1.GetDataSproc_Result'是一個 實體類型,但響應有效內容中的類型不代表 實體類型。請確保在客戶端上定義的類型匹配 服務的數據模型,或者更新 客戶端上的服務參考。

我通過引用實際的實體嘗試相同的事情 - 工作正常,所以同樣的問題。

回答

2

回顧:我想創建一個返回強類型存儲過程的高性能WCF服務DAL(數據訪問層)。我最初使用「WCF數據服務」項目來完成此項目。看起來好像有它的侷限性,並且在審查了不同ORM的performance metrics之後,我最終使用了Dapper來進行基本WCF服務中的數據訪問。

我第一次創建了* .edmx模型併爲我的sproc創建了POCO。

接着,我創建了一個基地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; 
      } 
     } 
    } 
} 

服務類:

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(); 
     } 
    } 
} 

...然後創建了一個簡單的控制檯應用程序顯示的數據:

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(); 
     } 
    } 
} 

我也用PetaPOCO來完成這個,的時間設置比小巧玲瓏 - 的幾行代碼:

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"); 
     } 
    } 
} 

我喜歡它的快速和簡單是建立PetaPOCO,但使用與精緻小巧的存儲庫模式將擴展多的企業項目更好。

從EDMX直接創建複雜對象也非常簡單 - 對於任何存儲過程,然後使用它們。

例如,我根據sq_mobile_profile_get_by_id sproc創建了名爲ProfileDetailsByID_Result的複雜類型返回類型。

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; 
     } 
    } 
} 

因此,使用精緻小巧一些EDMX實體一起似乎是一個不錯的快速的方法來得到的東西去。我可能弄錯了,但我不確定爲什麼微軟不這麼認爲 - 不支持OData的複雜類型。

--- UPDATE ---

於是,我終於得到了來自微軟,當我提出在一個月前這個問題的迴應:

我們所做的研究就這個問題和我們發現Odata客戶端 庫不支持複雜類型。因此,我很遺憾地通知你,我們沒有太多可以解決的問題。

*可選:爲了獲得針對此問題的解決方案,您必須使用Xml到Linq類方法來獲取複雜類型。

非常感謝您對此事的理解。如果您有任何問題,請告知 。如果我們能夠進一步提供幫助,請告訴我們。

最好的問候,

似乎很奇怪。