【问题标题】:How to consume a complex object from a sproc using WCF Data Services / OData?如何使用 WCF 数据服务/OData 从存储过程中使用复杂对象?
【发布时间】:2012-04-03 15:52:24
【问题描述】:

使用 WCF 数据服务(和最新的实体框架),我想从存储过程返回数据。返回的 sproc 字段与我的数据库中的任何实体都不匹配 1:1,因此我在 edmx 模型中为其创建了一个新的复杂类型(而不是附加现有实体):

  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 服务跟踪查看器打开,我看到两个相同的警告:

未找到配置评估上下文。

<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' 是一个 实体类型,但响应载荷中的类型不代表 实体类型。请确保客户端上定义的类型匹配 服务的数据模型,或更新服务引用 客户。

我通过引用实际实体尝试了同样的事情 - 工作正常,所以同样的问题。

【问题讨论】:

    标签: entity-framework c#-4.0 wcf-data-services


    【解决方案1】:

    回顾:我想创建一个返回强类型存储过程的高性能 WCF 服务 DAL(数据访问层)。我最初使用“WCF 数据服务”项目来完成此任务。似乎它有其局限性,在查看了不同 ORM 的 performance metrics 之后,我最终使用 Dapper 来访问基本 WCF 服务中的数据。

    我首先创建了 *.edmx 模型并为我的存储过程创建了 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 完成了这项工作,它的设置时间比 Dapper 少得多 - 几行代码:

    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 的快速和简单,但是将存储库模式与 Dapper 一起使用会更好地扩展企业项目。

    直接从 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;
            }
        }
    }
    

    因此,将 Dapper 与一些 EDMX 实体一起使用似乎是让事情顺利进行的好方法。我可能弄错了,但我不确定为什么 Microsoft 没有从头到尾考虑到这一点 - 不支持 OData 的复杂类型。

    --- 更新 ---

    所以当我在一个多月前提出这个问题时,终于得到了微软的回应:

    我们对此进行了研究,我们发现 Odata 客户端 库不支持复杂类型。因此,我很遗憾地通知 你说我们无能为力。

    *可选:为了获得此问题的解决方案,您必须使用 Xml to Linq 类型的方法来获取复杂类型。

    非常感谢您对此事的理解。请让 我知道你是否有任何问题。如果我们可以更进一步 帮助,请告诉我们。

    最好的问候,

    看起来很奇怪。

    【讨论】:

      猜你喜欢
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多