一.最近在使用Wcf创建数据服务,但是在和EF框架搭建数据访问时遇到了许多问题
下面是目前整理的基本框架代码,经供参考使用
说明:框架搭建中使用EF访问数据库,简单工厂模式组织代码
WCFThree.Entity:简单工厂模式的实体层、EF的实体模板、WCF的数据契约 WCFThree.Abstract:简单工厂模式的抽象接口层、WCF服务操作契约 WCFThree.Factory:简单工厂模式的实现层、WCF服务器契约实现 WCFThree.Proxy:WCF的客户端代理封装 WCFThree.Service:WCF的服务端定义 WCFThree.Test:测试程序
部分代码说明:
1.为了使客户端和服务端使用相同的代理类,EF框架中禁用动态代理类实例,同时延迟加载也失效
public BaseContext() : base("name=BaseContext") { //在Wcf中禁用EF的代理类和延迟加载 this.Configuration.ProxyCreationEnabled = false; }
2.为了解决序列化的循环引用问题,显示指定数据契约以及对应的属性,这样还有一个好处就是从服务端向客户端数据输出可以带着关联表数据(因为没法延迟加载,所以在服务器端需要再查询一次关联表数据)
[Table("student")] [DataContract(IsReference = true)] public partial class student { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] public student() { scores = new HashSet<score>(); } [Key] [StringLength(3)] [DataMember] public string sno { get; set; } [Required] [StringLength(100)] [DataMember] public string sname { get; set; } [StringLength(2)] [DataMember] public string ssex { get; set; } public DateTime? sbirthday { get; set; } [Column("class")] [StringLength(5)] [DataMember] public string _class { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] [DataMember] public virtual ICollection<score> scores { get; set; } }
3.客户端代理使用BasicHttpBinding创建
public class RemoteServiceFactory { private string GetUrl(string Operate) { return string.Format("http://localhost:8733/Design_Time_Addresses/WCFThree.Service/{0}/", Operate); } /// <summary> /// 获取学生操作 /// </summary> /// <returns></returns> public IStudent GetStudent() { string url = GetUrl("Student"); return CreateService<IStudent>(url); } public IScore GetScore() { return CreateService<IScore>(GetUrl("Score")); } public IUserInfo GetUserInfo() { return CreateService<IUserInfo>(GetUrl("UserInfo")); } private T CreateService<T>(string url) { var binding = new BasicHttpBinding(); binding.MaxReceivedMessageSize = maxReceivedMessageSize; binding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas(); binding.ReaderQuotas.MaxStringContentLength = maxReceivedMessageSize; binding.ReaderQuotas.MaxArrayLength = maxReceivedMessageSize; binding.ReaderQuotas.MaxBytesPerRead = maxReceivedMessageSize; ChannelFactory<T> chan = new ChannelFactory<T>(binding, new EndpointAddress(url)); //异常处理注册 //cha.Endpoint.EndpointBehaviors.Add(); foreach (var op in chan.Endpoint.Contract.Operations) { var dataContractBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>() as DataContractSerializerOperationBehavior; // 获取或设置对象图中要序列化或反序列化的最大项数。 if (dataContractBehavior != null) dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue; } chan.Open(); return chan.CreateChannel(); } private const int maxReceivedMessageSize = 2147483647; }
4.测试及结果说明
RemoteServiceFactory _remote = new RemoteServiceFactory(); IStudent _IStudent = _remote.GetStudent(); ////1.添加学生 WCFThree.Entity.student stu1 = new Entity.student() { sno = "110", sname = "李四", ssex = "男", sbirthday = DateTime.Now, _class = "95033" }; _IStudent.Add(stu1); ////2.获取列表 List<WCFThree.Entity.student> stuList = _IStudent.GetList(); foreach (var item in stuList) { //编号-姓名---学习的课程数量(获取关联表数据失效) Console.WriteLine(string.Format("{0}-{1}--{2}", item.sno, item.sname, item.scores.Count)); } //3.获取指定对象及关联数据----方式1:独立请求 WCFThree.Entity.student stu2 = _IStudent.GetModel("101"); Console.WriteLine(stu2.sname); IScore _IScore = _remote.GetScore(); List<WCFThree.Entity.score> scoreList = _IScore.GetList_Stu(stu2.sno); foreach (var item in scoreList) { Console.WriteLine(string.Format("{0}-{1}", item.sno, item.degree)); } //获取关联表数据方式2 WCFThree.Entity.student stu3 = _IStudent.GetModel_Related("101"); Console.WriteLine(stu3.sname); Console.WriteLine(stu3.scores.Count); Console.WriteLine(stu3.scores.First().degree);