2011-10-07 103 views
3

我有一个基本的服务类,并且我有一堆服务,在服务类中存储数据是好的还是不好的做法?在服务层中存储状态

例如:

public interface IFunkyService 
{ 
    void AddComment(int quoteid, string comment); 
    void SetProirirty(int quoteid, Importance proirity); 
} 

public class FunkyService : CustomServiceBase, IFunkyService 
{ 

private readonly IRepo _repo; 
private readonly IUserSession _user; 
public FunkyService(IRepo repo, IUserSession user) 
{ 
    _repo = repo; 
    _user = user; 
} 


    public void SetProirirty(int quoteid, Important priority) 
    { 

     //get quote object then persists 

    } 

    public void AddComment(int quoteid, string comment) 
    { 

     //get quote object then persists 

    } 

} 

我可以简单地只具有存储类上的报价对象的私有方法? 例如

private Quote _quote {get;set;} //store on the class??? 

private void GetQuote(int quoteid) 
{ 
_quote = _repo.single(quoteid); //or whatever 
} 

回答

2

请注意,类中的值只会与服务对象本身一样长。一个服务对象会随着服务的每一个请求被创建和销毁,所以Quote将只在一个请求的长度内生存。我可以看到的唯一目的就是每个请求缓存(即,在一次请求中,您引用Quote对象五次,您只需要从后台存储中查看一次)。

  1. 客户端发出请求,服务器
  2. 服务器实例FunkyService
  3. 客户端调用GetQuote
  4. Server中的类填充Quote
  5. 客户端完成呼叫。
  6. 服务器确认请求,配置(2)中的FunkyService对象。
  7. Quote的值不再存储在类中,因为该对象已消失。

编辑:看样子你想这样做是为了让检索引用对象在一个地方做的原因,但它不会被调用一遍又一遍(即,使多个请求数据库只需要一个时)。您可以实现可缓存属性设计模式以使每个请求缓存不使用类变量。它看起来像这样:

private Dictionary<int, Quote> _quoteCache = 
    new Dictionary<int, Quote>(); // cache storage - NEVER ACCESS DIRECTLY 

public Quote GetQuote(int quoteid) 
{ 
    // cache is invalid, so populate 
    if (!_quoteCache.ContainsKey(quoteid)) 
    { 
     _quoteCache.Add(quoteid, _repo.single(quoteid)); 
    } 

    // return back to caller 
    return _quoteCache[quoteid]; 
} 

在上面的示例中,缓存存储从数据库检索到的每个唯一的quoteid。因此,如果连续五次调用GetQuote(5),则只能通过_repo一次性从数据库中检索它。但是,如果您致电GetQuote(6),那么它将再次进入数据库,因为该引用在高速缓存中不可用。之后,5和6仍然存储在缓存中,直到服务请求完成并处理完毕。

EDIT2:在这个例子中,你提供:

var t = GetTags(_quote); 
// then do something with t, I may pass to another method: 
if(IsClosed(_quote)){} 

而不是引用类变量,有你的资料库返回一个Quote对象,并沿传递引用,就像这样:

private Quote GetQuote(int quoteid) 
{ 
    return _repo.single(quoteid); //or whatever 
} 

// other code 
var q = GetQuote(quoteid); // get the quote once 
var t = GetTags(q); // q doesn't have to retrieve from repo again 
if (IsClosed(q)) {} 
// etc. 
+0

对我来说,最大的好处就是让“在一个地方给我一个引用对象”,如果我调用一个方法或将对象传递给另一个方法,我不想每次重新实例化对象。在一个调用中,我想完成我的任务,如果权衡是我不能用这个对象再次调用(在7.完成之后),那很好。你怎么看? – Haroon

+0

我不确定我是否理解你。您应该可以将'Quote'对象从method传递到method,而不必一次又一次地从数据库中获取参数。如果你将它存储在类中以保持它作为实际上是一个坏主意**(如全局变量)的方法之间的引用。你能否添加一些代码来演示一个将被调用的方法链的例子? – mellamokb

+0

你绝对可以“在一个地方给我一个报价对象”,这没有什么错。但不是将其存储在全局类变量中,而是从方法'private Quote GetQuote(int quoteid){return _repo.single(quoteid); }'。然后将方法引用到方法。合理? – mellamokb

0

服务中有状态的问题是需要考虑服务类实例的生命周期。例如,如果您的服务是通过WCF公开的,那么'per call'的默认实例化模式将会否定方法调用之间的任何状态,因为每个调用都意味着从每个调用创建一个新的服务实例客户。但是,您可以使用InstanceContextMode.PerSession在呼叫之间“保持”客户端和服务之间的连接,这会给您带来一些状态的好处,但它也存在可扩展性受限的缺点,因为您的客户端现在最终控制您所在州使用的服务器资源。

@ mellamokb的观点非常好,因为SOA中状态的一个常见用途是缓存。

1

不知道这是否适用于你的情况,但切换时无状态的服务(或通常的任何成分)是有状态的,你需要考虑以下几个问题:

  1. 线程安全 - 你必须把状态不变确保线程安全访问该状态。另外请记住,大多数跟踪(状态跟踪)ORM在从多个线程访问相同实例时效果不佳。
  2. 考虑将来可能会在多个实例中部署该服务(比如负载均衡)。如果状态不是不可变的,那么最终会出现同一个实体的不同步实例。
  3. 如果这样做的原因是缓存和性能改进,您可以设计一个正交缓存策略,以避免上述问题 - 例如使用NHibernate缓存提供程序或缓存应用程序层中的数据。

作为一条经验法则,尽量保持代码无状态。与其合作更安全,可以通过执行异步操作来提高性能,并且我认为其他人更容易理解它。当你需要保持状态,尤其是共享状态时,确保所有对它的访问都是线程安全的,并且有很好的文档记录。

+0

因此,即使我必须多次访问数据库才能访问数据库,这比存储对象实例更安全吗?我正在使用Linq To Sql,我不确定对缓存的支持是否有好处。 – Haroon

+0

你会说@mellamokb提供的例子足够好吗?我的意思是,所有我对一个asp.net mvc动作方法的调用通常都会在一个web请求中(并没有真正设置好这个),所以我不觉得这些实体会不同步,你怎么看?为了强调,我只打算在一个Web请求中调用服务和相关代码,在另一个Web请求中,我不介意再次调用数据库,(在我的头上),这意味着我失去了缓存能力,但它不是太糟糕对我而言......思念? – Haroon

+0

我已经完成了只有摘要测试,但它接缝linq2sql在上下文级别实现标识映射,所以如果您多次查询同一个id的相同上下文,只有第一次执行查询,并且其余查询相同返回对象的实例 - 只要您在L2S数据上下文的同一实例上执行查询,您不必担心保持状态,因为linq会为您执行此操作。作为(另一种)经验法则,如果没有硬性事实和测量数字,不会进行优化。 –