2012-04-03 3 views
5

Sử dụng dịch vụ dữ liệu WCF (và khung thực thể mới nhất), tôi muốn trả về dữ liệu từ một thủ tục được lưu trữ. Các trường sproc được trả về không khớp với bất kỳ thực thể nào trong db của tôi, vì vậy tôi tạo một kiểu phức hợp mới cho nó trong mô hình edmx (thay vì gắn một thực thể hiện có):Làm thế nào để tiêu thụ một đối tượng phức tạp từ một sproc bằng cách sử dụng dịch vụ dữ liệu WCF/OData?

  1. Nhấp chuột phải vào *. edmx mô hình/Add/Chức năng Import
  2. Chọn sproc (trả về ba lĩnh vực) - GetData
  3. Bấm Get Thông tin Cột
  4. Thêm Chức năng Import Name: GetData
  5. Bấm Tạo Kiểu Complex mới - GetData_Result

Trong dịch vụ, tôi xác định:

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

Tôi tạo ra một giao diện điều khiển ứng dụng nhanh chóng để kiểm tra, và thêm một tham chiếu đến System.Data.ServicesSystem.Data.Services.Client - điều này sau khi chạy Install-Package EntityFramework -Pre, nhưng các phiên bản trên các thư viện là 4.0 và không 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(); 
     } 
    } 
} 

Tôi không sử dụng số UriKind.Relative hoặc bất kỳ điều gì khác để làm phức tạp điều này.

Khi tôi điều hướng trong trình duyệt đến URL, tôi thấy dữ liệu, nhưng khi tôi sử dụng nó trong ứng dụng bảng điều khiển của mình, tôi hoàn toàn không nhận được gì.

Thêm tracing để trộn:

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

... và mở cửa bằng cách sử dụng Microsoft Dịch vụ vết Viewer, tôi thấy hai cảnh báo idential: không tìm thấy

Cấu hình bối cảnh đánh giá.

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

Vì vậy, tại sao tôi lại có thể xem dữ liệu từ trình duyệt, nhưng không phải khi tiêu thụ trong ứng dụng của tôi?

- CẬP NHẬT -

Tôi đã tải về Microsoft WCF Data Services October 2011 CTP mà tiếp xúc DataServiceProtocolVersion.V3, tạo ra một máy chủ mới và khách hàng và tham chiếu Microsoft.Data.Services.Client (v4.99.2.0). Bây giờ nhận được lỗi sau trên máy khách khi thử lặp lại trong vòng lặp foreach:

Có loại không phù hợp giữa khách hàng và dịch vụ. Loại 'ConsoleApplication1.WcfDataServiceOctCTP1.GetDataSproc_Result' là loại thực thể , nhưng loại trong tải trọng phản hồi không đại diện cho loại thực thể. Vui lòng đảm bảo rằng các loại được xác định trên đối tượng khách hàng mô hình dữ liệu của dịch vụ hoặc cập nhật tham chiếu dịch vụ trên ứng dụng .

Tôi đã thử điều tương tự bằng cách tham chiếu thực thể thực tế - hoạt động tốt, cùng vấn đề.

Trả lời

2

Tóm tắt: Tôi muốn tạo một dịch vụ WCF hiệu năng cao DAL (lớp truy cập dữ liệu) trả về các thủ tục được lưu trữ mạnh mẽ. Ban đầu tôi đã sử dụng dự án "Dịch vụ dữ liệu WCF" để thực hiện việc này. Dường như nó có những hạn chế của nó, và sau khi xem xét performance metrics của ORM khác nhau, tôi đã kết thúc bằng cách sử dụng Dapper để truy cập dữ liệu bên trong một Dịch vụ WCF cơ bản.

Lần đầu tiên tôi tạo mô hình * .edmx và tạo POCO cho sproc của tôi.

Tiếp theo, tôi đã tạo ra một BaseRepository cơ sở và 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; 
      } 
     } 
    } 
} 

Lớp dịch vụ:

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

... và sau đó tạo ra một ứng dụng giao diện điều khiển đơn giản để hiển thị dữ liệu:

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

Tôi cũng đã thực hiện việc này bằng cách sử dụng PetaPOCO, mất nhiều s thời gian để thiết lập hơn Dapper - một vài dòng mã:

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

Tôi thích cách nhanh chóng và đơn giản nó là để thiết lập PetaPOCO, nhưng sử dụng các mô hình kho với Dapper sẽ có quy mô tốt hơn nhiều cho một dự án doanh nghiệp. Nó cũng khá đơn giản để tạo các đối tượng phức tạp trực tiếp từ EDMX - cho bất kỳ thủ tục lưu sẵn nào, sau đó tiêu thụ chúng.

Ví dụ: tôi đã tạo loại trả về loại phức tạp được gọi là ProfileDetailsByID_Result dựa trên số sp2 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; 
     } 
    } 
} 

Vì vậy, việc sử dụng Dapper cùng với một số thực thể EDMX có vẻ là một cách nhanh chóng để thực hiện mọi thứ. Tôi có thể bị nhầm lẫn, nhưng tôi không chắc tại sao Microsoft lại không nghĩ điều này thông qua - không hỗ trợ cho các kiểu phức tạp với OData.

--- Cập nhật ---

Vì vậy, cuối cùng tôi nhận được một phản hồi từ Microsoft, khi tôi đưa ra vấn đề hơn một tháng trước:

Chúng tôi đã thực hiện nghiên cứu về vấn đề này và chúng tôi đã thấy rằng thư viện khách hàng Odata không hỗ trợ các loại phức tạp. Do đó, tôi rất tiếc phải thông báo cho rằng bạn không thể làm gì để giải quyết nó.

* Tùy chọn: Để có giải pháp cho vấn đề này, bạn phải sử dụng phương pháp tiếp cận Xml để LINQ để có được các loại phức tạp.

Cảm ơn bạn rất nhiều vì sự hiểu biết của bạn về vấn đề này. Vui lòng để tôi biết nếu bạn có bất kỳ câu hỏi nào. Nếu chúng tôi có thể được hỗ trợ thêm , vui lòng cho chúng tôi biết.

Trân trọng,

Có vẻ kỳ quặc.