davin

Just a little thinking and interest!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

     写在之前,这是3月份断断续续写的一些东西,最近一直在忙做mvc的应用,没有时间整理,乘着假期就把它整理出来,以便更好的交流。

     之前还不了解wcf的时候,就常常在EF Design team blog上和adodotnetentityframework社区看到一些关于EF在wcf场景中的应用的话题和文章。因为一直很关注EF,所以很想知道在wcf中是怎样在应用的。想从互联网上找些代码示例看看,不过没有什么收获。之后在学习wcf时,在new WCF features in .NET 3.5 SP1 了解到 WCF完全支持POCO(Support for ADO.NET Entity Framework entities in WCF contracts尽管到现在我知道POCO的定义是Plain old c# Object,可还没搞清无法理解和何为POCO),这让我更有了尝试的冲动,可是当写完测试方法后,我照例使用wcftestclient工具来调用,可居然发现如图所示,无法调用而我的契约则是这样声明的:

图1

[OperationContract]

  string GetCategoryById(int categoryID);

  [OperationContract]

  NorthWind.Categories GetCategoryById1(int categoryID);

  [OperationContract]

  void GetCategoryById2(int categoryID, out NorthWind.Categories obj); 

  [OperationContract]

  string DoWork();

  [OperationContract]

 Student GetStudent(string id)

     当然对于自定义的DTO对象(GetPerson(),DoWork()),调用则正常。添加一个控制台客户端,创建一个代理可以调用上面的方法,GetStudent()都正常,调用和EF相关的方法,但是报错,我又不知无法debug,在使用wcftestclient调用.svc的服务时,直接可以debug的。这些问题不仅让我郁闷还让我很奇怪,为什么会这样呢,是我哪里做的不对?后来在codeplex找到一个叫besocia 开源项目(关于ef和wcf ),不过打开代码查看,发现里面是用传统的方法,自定义传输对象在完成(没有别的意思,只是那不是我想看到的),不过后来我想是不是由于返回值的原因,于是我定义了GetCategoryById(),GetCategoryById1(),GetCategoryById2()三个不同返回类型的方法,而在wcftestclient下面显示的结果则如图1。

     不过后来由于工作的原因,也没什么心思去折腾这个,新公司里,我接替前辈留下的工作,慢慢开始接触silverlight+wcf+linq to sql的应用环境,看到前辈定义的那些DTO对象,我暗自感慨,为wcf传输定义的那些DTO传输对象真是一个麻烦的过程,后来在 zeeshanhirani(http://weblogs.asp.net/zeeshanhirani )看到一篇关于linq to sql的探讨entityRef的问题,提到可以通过设置datacontext的Serialization Mode设置为Unidirectional就可以让linq to sql生成的实体具备在wcf序列化的能力(在实体类之前可以清楚的看到[DataContract()]标签),并且这一特性在EF中得到了加强,即是EF生成的实体自身就具备序列化的能力。在了解这些之后,我找出之前的练习,看到stackoverflow上关于wcf在ef上的应用,我就很郁闷为什么我会有图1的错误,我尝试在写一个控制台的client来调用,居然成功了GetCategoryById1()成功( 我是这样调用proxy.GetCategoryById1(1);没报错 ),看来之前没能成功都是因为偷懒造成的。在ef中是通过 [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)],    [global::System.Runtime.Serialization.DataMemberAttribute()],这2个标签来支持wcf传输的,当然这是我后来才认识到的。因此下班之后,我又开始折腾了,在silverlight论坛里看到一些人在讨论silverlight+wcf+entity framework的应用,居然有人在和遭遇同样的问题同样的问题,提问也没有人告诉我为什么,不过还是得到了一些建议,比如在wcf service项目的config文件下添加

 <system.web >

   <compilation debug="true"></compilation>

  </system.web>这个节点,就可以启动远程调试。能调试就好办多了

 

     下面是ef在wcf中的一些不同寻常的地方,至少我拿linq to sql 和EF 比较,因为linq to sql当设置了Serialization Mode为Unidirectional后,在wcf中应用和自定义DTO没什么不同。我只是个菜鸟,只是喜欢瞎折腾而已,因此只能列举现象;

   1.EF实体类型在wcf客户端无法直接使用:为wcf定义的传输对象通常会被序列化在serviceReference ,在上面调用GetCategoryById1(),我想把返回结果赋值给一个Categories 对象,可是在CategoryReference下找不到任何有关EF的实体类型(自定义的student对象除外),我甚至使用是svcutil工具在生成的.axd文件中查看定义,的确实没有,因此只好把结果返回给var 如 var cc = proxy.GetCategoryById1(1); c = cc.CategoryName;,难道说非得手动添加edmx文件的引用?至少目前我是这样做,不过感觉有点怪怪的,

不过这样就保证了在服务端和客户端实体的统一,似乎在efdesign blog上n-tier-improvements-for-entity-framework这边文章中分析了DTO,DataSet在应用场景中的优缺点,特别提到DTO在客户端是完全独立的,不依赖服务端,这样构成了一个信任边界,适合应用于不同的公司,而ef则可以应用于完全信任的多层应用中,不见得上面的观点都正确,但对于我而言可以得到足够的启发

  2.out,ref参数返回居然会被替换(都不知如何去描述描述),如上面例子void GetCategoryById2(int categoryID, out NorthWind.Categories obj); 我在使用proxy..GetCategoryById2(),明明是2个参数,却变成一个我查看,我查看CategoryReference下GetCategoryById2的定义:

 public NorthWind.Categories GetCategoryById2(int categoryID) {

            return base.Channel.GetCategoryById2(categoryID);

        }基本上和GetCategoryById1一样,不过后来使用linq to sql试了一下,也是这种情况,对于自定义的DTO也是这样,看来这是wcf内部处理了。

 3.object graphs (不知如何称呼);在stackoverfolw社区和silverlight论坛上看到有人询问这个话题,在.net3.5sp1里面,ef这个特性已经完全支持,我也做了一个小测试 :

  [OperationContract]

    NorthWind.Orders GetOrderByID1();

[OperationContract]

NorthWind.Orders GetOrderByID();

  public NorthWind.Orders GetOrderByID1()

   {

    using (NorthWind.NorthwindEFEntities context = new NorthWind.NorthwindEFEntities())

     {

      return context.Orders.FirstOrDefault<NorthWind.Orders>();

    }

   }

  public NorthWind.Orders GetOrderByID()

  {

  using (NorthWind.NorthwindEFEntities context = new NorthWind.NorthwindEFEntities())

     {

      return context.Orders.Include("OrderDetails").FirstOrDefault();//<NorthWind.Orders>

     }

   }

Client:

 OrderReference.OrdersContractClient proxy = new Client.OrderReference.OrdersContractClient();

   var order = proxy.GetOrderByID();

   Console.WriteLine("OrderDetailes {0}", order.OrderDetails.Count);

  order = proxy.GetOrderByID();

  Console.WriteLine("OrderDetailes {0}", order.OrderDetails.Count);

 

   4.CURD:在curd练习中,最有感慨的莫过于对于实体的更新,其实这也是目前ef1.0在n层应用上的欠缺,在ms 08年12月份的杂志上的Flexible Data Access With LINQ To SQL And The Entity Framework,N-Tier Improvements for Entity Framework 

这2篇文章中对EF在n层应用做了一些探讨。文中提到EF在n层应用中最难以处理的地方就是更新实体时,必须给定原始值(跟新之前的实体)和当前值(当前实体),应为在应用程序中我们更本不知道那些实体的属性被更新了,只能把每一个当前实体的属性相比原始值都是被更新的,显然实体clone也是也个解决方法。当然如果使用EntityDataSource就没有这种烦恼了。另外一个问题就是并发(concurrency).当然这些现在对于我而言已经很明白了,当然在dsimmons的blog上一篇名为AttachAsModified – a small step toward simplifying EF n-tier patterns 的文章,似乎提供了一个很好的解决方案 ,我为了能理解dsimmonss的一些评述,曾不止一次的阅读以上提到的几篇文章。在现在我进行的web项目中(mvc+EF)已经得到很好的使用.在之后我将会把这部分详细的写出来。

posted on 2009-05-03 00:29  davin  阅读(3711)  评论(3编辑  收藏  举报