2011-10-07 71 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會爲您執行此操作。作爲(另一種)經驗法則,如果沒有硬性事實和測量數字,不會進行優化。 –