更新一个WCF调用中的许多实体,而不是为每个要更新的实体命中WCF服务

时间:2012-10-23 17:28:23

标签: c# wcf entity-framework

我在多层应用程序上工作,我需要以三种方式优化长时间运行的流程:

  1. 避免EF更新并发问题。
  2. 提高速度。
  3. 告知用户进度。
  4. 实际上,客户端代码使用完成所有工作的方法调用WCF服务评估要更新的实体数量查询实体到更新更新,最后将它们保存回数据库。)

    该过程非常漫长,并且完成此过程后,除了最终结果之外,不会向用户发送任何内容。用户可以在等待表格前停留长达10分钟,不知道发生了什么。

    查询实体的数量和深度可能变得非常大,我有时会遇到OutOfMemoryExceptions。我不得不一次更改服务方法来处理实体更新100个实体,因此我的DbContext将经常刷新并且不会变得太大。

    我的实际问题是,每次更新实体时都无法通知用户,因为我的服务方法在将结果返回给用户之前完成整个过程。

    我读过关于实现双工服务但是因为我必须向用户返回两个不同的回调(一个回调返回要更新的实体数量和另一个回调每个实体更新的结果)我必须在通用回调接口上使用多个接口继承,它变得有点混乱(根据我的口味)。

    让一个WCF服务方法返回要评估的实体数量,以及另一个返回简单实体更新结果的WCF方法不是更好吗?每个实体都要更新结果?我的DBContext只能在单个实体更新时生存,因此它不会增长很多,我认为这是好的。 但是,我担心在此过程中经常经常访问WCF服务

    你有什么想法?你有什么建议吗?

2 个答案:

答案 0 :(得分:0)

  1. 避免EF更新并发问题。

    请参阅此问题/答案Long running Entity Framework transaction

  2. 提高速度。

    一些建议:

    • 尝试使用SQL事件探查器查看正在执行的SQL查询,并优化linq查询
    • 或尝试改进查询本身或调用存储过程。
    • 可以并行完成更新吗?不同的线程?不同处理器?
  3. 告知用户进度。

    我建议更改客户端以调用异步方法,或者以异步方式启动长时间运行的方法。这会立即将控制权返回给客户端。然后,由长时间运行的操作来提供有关其进度的反馈。

    请参阅此文章了解updating progress from a background thread

    更新
    我建议的“架构”如下:

  4.               . Service . . .
        ________  .    _________    _______    ____
       |        | .   |   WCF   |  |  EF   |  |    |
       | Client |---->| Service |->| Class |->| DB |
       |________| .   |_________|  |_______|  |____|
                  .
                  . . 
    

    WCF服务仅负责接受客户端请求,并启动EF类中的长时间运行操作。客户端应该向WCF服务发送异步请求,以便保留控制和响应。 EF类负责更新数据库,您可以选择一次更新所有子集或记录。然后,EF类可以根据需要通过WCF服务通知客户端它所取得的任何进展。

答案 1 :(得分:0)

您是否考虑过向您的客户端添加WCF主机?这样你就可以获得完全双向的通信。

客户端连接到服务器并将服务器连接详细信息返回给客户端
客户请求长时间运行操作开始 随着工作的进展,服务器会向客户端WCF主机发送多个更新 服务器将工作完成发送给客户端。

这使您的客户可以自由地做其他事情,在您认为合适的情况下使用来自服务器的消息。也许在消息进入时更新状态区域。

您甚至可以让服务器维护客户端列表并向其发送更新。

--------编辑---------
当我说WCF主机时,我的意思是ServiceHost 它可以通过App.config中的XML自动创建,也可以直接通过代码创建。

var myUri = new Uri[0];
myUri[0] = new Uri("net.tcp://localhost:4000");
var someService = new SomeService(); //implements ISomeService interface
var host = new ServiceHost(someService, myUri);
var binding = new NetTcpBinding(); // need to configure this
host.AddServiceEndpoint(typeof(ISomeService), binding, "");
host.Open();

代理是我用来连接服务器的一个术语,这是我遇到过的一个早期的例子,从那以后它一直困扰着我。可以两种方式创建。

var binding = new NetTcpBinding(); // need to configure this
var endpointAddress = new EndpointAddress("net.tcp://localhost:4000");
var factory = new ChannelFactory<ISomeService>(binding, endpointAddress);
var proxy = factory.CreateChannel();
proxy.DoSomeWork();

所以在一个典型的客户端/服务器应用程序中你有

CLIENT APP 1       SERVER APP         CLIENT APP 2
proxy------------->ServiceHost<-------proxy

我的建议是,您可以将客户端变为“服务器”

CLIENT APP 1       SERVER APP         CLIENT APP 2
proxy------------->ServiceHostA<------proxy
ServiceHostB<------proxy1
                   proxy2------------>ServiceHostB

如果你这样做,你仍然可以根据需要将你的大任务拆分成较小的任务(你提到了内存问题),但从事情的声音来看,他们仍然可能需要一些时间,这样进度更新仍然可以发回如果您希望每个人都知道发生了什么,客户甚至是所有客户。不需要回调,但如果你愿意,你仍然可以使用它们。