ServiceStack.Redis 中關係操作的局限與bug

來源:互聯網
上載者:User

標籤:

redis是文檔型的,nosql中難處理的是關係。

比如人可以發部落格,部落格可以有分類。按照傳統sql中,使用者表和分類表都是主表,部落格表是從表,有使用者的外鍵和分類的外鍵

如果使用文檔型的思考方式。

為使用者A(User id=1)儲存他的部落格,在redis中是list或set

為分類A(Cate id=1)存放裝置分類下的部落格,在redis中是list或set

則當使用者A向分類A中添加一條新部落格時,需要同時向兩個list(或set)中增加資料,而且理論上應該是事務的,修改的時候也需要同時修改兩個。

這樣的好處是讀操作是完全最佳化的,直接從一個key中讀出來的東西,馬上就可以用

壞處是寫操作太複雜,稍不注意可能就漏掉什麼東西,更新部落格需要更新非常多個list中的元素。

 

ServiceStack的redis用戶端專門為這種情況提供了幾個方法。

先來看實體類

public class User{    public int Id { get; set; }    public string Name { get; set; }}public class Blog{    public int Id { get; set; }    public string Title { get; set; }}public class Cate{    public int Id { get; set; }    public string Name { get; set; }}

很簡單的3個類,用於表示使用者,分類,部落格3種概念

使用強型別的client儲存3個執行個體

var clientsManager = new PooledRedisClientManager();using (IRedisClient redis = clientsManager.GetClient()){    redis.FlushAll();    var u = new User { Id = 1, Name = "A" };    var c = new Cate { Id = 1, Name = "A" };    var blog = new Blog { Id = 1, Title = "blog" };    redis.As<User>().Store(u);    redis.As<Cate>().Store(c);    redis.As<Blog>().Store(blog);}

可以通過用戶端軟體查看,3個實體都儲存成功,但是並沒有體現關係

redis.As<User>().StoreRelatedEntities(u.Id, blog);redis.As<Cate>().StoreRelatedEntities(c.Id, blog);

之後調用儲存關係的語句,as的是主表,第一個是主表主鍵,第二個是從對象

redis中,建立了2個key,ref:Cate/Blog:1和ref:User/Blog:1

他們的值是一個set

set中的具體內容並不是對象本身,而是對象在urn中的key

 

 

var blogs = redis.As<User>().GetRelatedEntities<Blog>(u.Id);

可以通過相關語句來擷取從表內容

直接取到了blog的實體

 

但是在刪除的時候有一個bug

他的方法指定的第二個參數是childId,所以我們傳進去id,但是刪除不掉

 

redis.As<User>().DeleteRelatedEntity<Blog>(u.Id, blog);

不使用id,而使用對象,也依然刪除不掉

查看源碼發現,當他運行從set中刪除東西的時候,找key是對的,但是要被刪掉的元素產生的不對

添加的時候,他拿UrnKey<T>(x)產生了實體儲存的key,而刪除的時候沒有

刪除的時候,直接是序列化的,則1,序列化後就是1,而我們的set中,並沒有1這個值,所以是沒有刪掉任何東西的。

client的UrnKey是個internal的方法,再次被噁心了

redis.As<User>().DeleteRelatedEntity<Blog>(u.Id, (redis as RedisNativeClient).NamespacePrefix + IdUtils.CreateUrn(blog));

我們只能使用這麼複雜的方式,等於把他內部的代碼都拿到外面來處理了,當然你可以clone他的源碼去改或者寫擴充方法。

 

 

根據關係的key,我們大概可以分析出

ref:主表/從表:主表主索引值

但這樣的方式有一定的局限性,就是對同一個主從類型,他們之間只能表達一種關係。

比如人與部落格,如果我需要表達 人寫的部落格,人推薦的部落格 這兩種關係(都是人與部落格的),則無法實現

比如User 1,他寫了Blog 1,推薦了Blog 2。但是他們都會被加入到ref:User/Blog:1中,無法區分是他寫的還是他推薦的。

所以我們需要為兩種類型之間的關係去給一個名字,來區分到底是那種關係

 

在RedisTypedClient<T>中有一個GetChildReferenceSetKey方法,是來產生這個key的,private方法,再次被噁心

當然,可以通過對NamespacePrefix設定一個不同的值來區分,但是感覺上怪怪的,因為這個在我看來是不同的應用程式,為防止key重複而設定的

有興趣的朋友可以寫幾個擴充方法,反正源碼基本都能看到

 

再再再次被噁心到的是,竟然github沒有開放issues提交

ServiceStack.Redis 中關係操作的局限與bug

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.