ElH*_*aix 5 entity-framework wcf-data-services c#-4.0
使用WCF数据服务(和最新的实体框架),我想从存储过程返回数据.返回的sproc字段与我的数据库中的任何实体都不匹配1:1,因此我在edmx模型中为它创建了一个新的复杂类型(而不是附加现有实体):
在服务中,我定义:
[WebGet]
public List<GetData_Result> GetDataSproc()
{
PrimaryDBContext context = new PrimaryDBContext();
return context.GetData().ToList();
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个快速控制台应用程序来测试,并在运行后添加了对 - System.Data.Services
和System.Data.Services.Client
this 的引用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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我没有使用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>
Run Code Online (Sandbox Code Playgroud)
...并使用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>
Run Code Online (Sandbox Code Playgroud)
那么为什么我能够从浏览器中看到数据,而不是在我的应用程序中使用时?
- 更新 -
我下载了2011微软WCF数据服务月CTP里面露出DataServiceProtocolVersion.V3
,创造了一个新的主机和客户端和参考Microsoft.Data.Services.Client(v4.99.2.0).现在,在循环中尝试迭代时,在客户端上收到以下错误foreach
:
客户端和服务之间存在类型不匹配.类型"ConsoleApplication1.WcfDataServiceOctCTP1.GetDataSproc_Result"是实体类型,但响应有效内容中的类型不表示实体类型.请确保客户端上定义的类型与服务的数据模型匹配,或更新客户端上的服务引用.
我通过引用实际实体尝试了同样的事情 - 工作得很好,同样的问题.
回顾:我想创建一个返回强类型存储过程的高性能 WCF 服务 DAL(数据访问层)。我最初使用“WCF 数据服务”项目来完成此任务。它似乎有其局限性,在审查了不同 ORM 的性能指标后,我最终使用Dapper在基本 WCF 服务内进行数据访问。
\n\n我首先创建了 *.edmx 模型并为我的存储过程创建了 POCO。
\n\n接下来,我创建了一个基础 BaseRepository 和 MiscDataRepository:
\n\nnamespace WcfDataService.Repositories\n{\n public abstract class BaseRepository\n {\n protected static void SetIdentity<T>(IDbConnection connection, Action<T> setId)\n {\n dynamic identity = connection.Query("SELECT @@IDENTITY AS Id").Single();\n T newId = (T)identity.Id;\n setId(newId);\n }\n\n protected static IDbConnection OpenConnection()\n {\n IDbConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["PrimaryDBConnectionString"].ConnectionString);\n connection.Open();\n return connection;\n }\n }\n}\n\nnamespace WcfDataService.Repositories\n{\n public class MiscDataRepository : BaseRepository\n {\n public IEnumerable<GetData_Result> SelectAllData()\n {\n using (IDbConnection connection = OpenConnection())\n {\n var theData = connection.Query<GetData_Result>("sprocs_GetData", \n commandType: CommandType.StoredProcedure);\n\n return theData;\n }\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n服务等级:
\n\nnamespace WcfDataService\n{\n public class Service1 : IService1\n {\n private MiscDataRepository miscDataRepository;\n\n public Service1()\n : this(new MiscDataRepository())\n {\n }\n\n public Service1(MiscDataRepository miscDataRepository)\n {\n this.miscDataRepository = miscDataRepository;\n }\n\n public IEnumerable<GetData_Result> GetData()\n {\n return miscDataRepository.SelectAllData();\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n...然后创建一个简单的控制台应用程序来显示数据:
\n\nnamespace ConsoleApplication1\n{\n class Program\n {\n static void Main(string[] args)\n {\n Service1Client client = new Service1Client();\n IEnumerable<GetData_Result> result = client.GetData();\n foreach (GetData_Result d in result)\n {\n Console.WriteLine(d.ID + "\\t" + d.WHO_TYPE_NAME + "\\t" + d.CREATED_DATE);\n }\n Console.Read();\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n我还使用PetaPOCO完成了此任务,它的设置时间比 Dapper 少得多 - 只需几行代码:
\n\nnamespace PetaPocoWcfDataService\n{\n // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.\n public class Service1 : IService1\n {\n public IEnumerable<GetData_Result> GetData()\n {\n var databaseContext = new PetaPoco.Database("PrimaryDBContext"); // using PetaPOCO for data access\n databaseContext.EnableAutoSelect = false; // use the sproc to create the select statement\n\n return databaseContext.Query<GetData_Result>("exec sproc_GetData");\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n我喜欢设置 PetaPOCO 的快速和简单,但是将存储库模式与 Dapper 一起使用将更好地扩展企业项目。
\n\n直接从 EDMX 创建复杂对象也非常简单 - 对于任何存储过程,然后使用它们。
\n\n例如,我创建了ProfileDetailsByID_Result
基于sq_mobile_profile_get_by_id
存储过程调用的复杂类型返回类型。
public ProfileDetailsByID_Result GetAllProfileDetailsByID(int profileID)\n{\n using (IDbConnection connection = OpenConnection("DatabaseConnectionString"))\n {\n try\n {\n var profile = connection.Query<ProfileDetailsByID_Result>("sq_mobile_profile_get_by_id",\n new { profileid = profileID },\n commandType: CommandType.StoredProcedure).FirstOrDefault();\n\n return profile;\n }\n catch (Exception ex)\n {\n ErrorLogging.Instance.Fatal(ex); // use singleton for logging\n return null;\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n因此,将 Dapper 与一些 EDMX 实体一起使用似乎是一种让事情顺利进行的快速方法。我可能是错的,但我不确定为什么 Microsoft 没有彻底考虑到这一点 - OData 不支持复杂类型。
\n\n- - 更新 - -
\n\n所以当我一个多月前提出这个问题时,我终于得到了微软的回复:
\n\n\n\n\n我们对此进行了研究,发现 Odata 客户端库不支持复杂类型。因此,我很遗憾地通知您,我们无能为力来解决这个问题。
\n\n*可选:为了获得此问题的解决方案,您必须使用 Xml to Linq 类型的方法来获取复杂类型。
\n\n非常感谢您对此事的理解。如果您有任何疑问,请告诉我。如果我们可以提供任何进一步的帮助,请告诉我们。
\n\n此致,
\n
看起来很奇怪。
\n