XPO:Session管理与缓存--测试篇

本文通过两个测试案例详细探讨了DevExpress XPO框架中Session管理和缓存机制的具体表现,包括对象在不同Session间的行为、刷新机制的限制及缓存管理策略,为开发者提供实践指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前整理了一下XPO在Session管理和缓存方面的一些资料(XPO:Session管理与缓存--机制篇),但原文的例程还是有些含糊的地方,这两天抽空做了一下测试。若有不当或者不对的地方敬请不吝赐教。

 

XPO初始化的代码就不重复贴了,这里只贴上主要的代码。

测试中构建了2个简单的类,XpoUser和XpoOrder,一对多的关系。

ExpandedBlockStart.gif XpoUser
using  System;
using  DevExpress.Xpo;

namespace  Model
{
    
public   class  XpoUser : XPObject
    {
        
public  XpoUser()
            : 
base ()
        {
            
//  This constructor is used when an object is loaded from a persistent storage.
            
//  Do not place any code here.
        }

        
public  XpoUser(Session session)
            : 
base (session)
        {
            
//  This constructor is used when an object is loaded from a persistent storage.
            
//  Do not place any code here.
        }

        
public   override   void  AfterConstruction()
        {
            
base .AfterConstruction();
            
//  Place here your initialization code.
        }

        
private   string  _Name;
        
public   string  Name
        {
            
get
            {
                
return  _Name;
            }
            
set
            {
                SetPropertyValue(
" Name " ref  _Name, value);
            }
        }

        [Association(
" XpoUser-Orders " )]
        
public  XPCollection < XpoOrder >  Orders
        {
            
get
            {
                
return  GetCollection < XpoOrder > ( " Orders " );
            }
        }
    }
}

 

 

 

ExpandedBlockStart.gif XpoOrder
using  System;
using  DevExpress.Xpo;

namespace  Model
{
    
public   class  XpoOrder : XPObject
    {
        
public  XpoOrder()
            : 
base ()
        {
            
//  This constructor is used when an object is loaded from a persistent storage.
            
//  Do not place any code here.
        }

        
public  XpoOrder(Session session)
            : 
base (session)
        {
            
//  This constructor is used when an object is loaded from a persistent storage.
            
//  Do not place any code here.
        }

        
public   override   void  AfterConstruction()
        {
            
base .AfterConstruction();
            
//  Place here your initialization code.
        }

        
private   string  _OrderID;
        
public   string  OrderID
        {
            
get
            {
                
return  _OrderID;
            }
            
set
            {
                SetPropertyValue(
" OrderID " ref  _OrderID, value);
            }
        }

        
private  XpoUser _User;
        [Association(
" XpoUser-Orders " )]
        
public  XpoUser User
        {
            
get
            {
                
return  _User;
            }
            
set
            {
                SetPropertyValue(
" User " ref  _User, value);
            }
        }
    }
}

 

 

 

做了两个测试,测试一的代码:

ExpandedBlockStart.gif Test1
            ClearDB();
            StringBuilder sb 
=   new  StringBuilder();
            Session s1 
=   new  Session();
            Session s2 
=   new  Session();
            XpoUser user1 
=   new  XpoUser(s1) { Name  =   " UserName "  };
            user1.Save();
            XpoUser user2 
=  s2.FindObject < XpoUser > ( new  BinaryOperator( " Name " " UserName " ));
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));

            sb.AppendLine(Environment.NewLine 
+   " Change user's name in Session 1 " );
            user1.Name 
=   " New UserName " ;
            user1.Save();
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));

            sb.AppendLine(Environment.NewLine 
+   " Create / Read something else(XpoRole) in Session 2 " );
            XpoRole role 
=   new  XpoRole(s2) { Name  =   " RoleName "  };
            role.Save();
            role 
=  s2.FindObject < XpoRole > ( new  BinaryOperator( " Name " " RoleName " ));
            sb.AppendLine(
string .Format( " Role name : {0} " , role.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));

            sb.AppendLine(Environment.NewLine 
+   " Create / Read another XpoUser in Session 2 " );
            XpoUser anotherUser 
=   new  XpoUser(s2) { Name  =   " Another User "  };
            anotherUser.Save();
            anotherUser 
=  s2.FindObject < XpoUser > ( new  BinaryOperator( " Name " " Another User " ));
            sb.AppendLine(
string .Format( " Another user's name : {0} " , anotherUser.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));

            sb.AppendLine(Environment.NewLine 
+   " Try to Save the user in Session 2, which is modified in Session 1 " );
            
try
            {
                user2.Save();
            }
            
catch  (Exception ex)
            {
                sb.AppendLine(ex.Message);
            }
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));

            sb.AppendLine(Environment.NewLine 
+   " Session.Reload(User) in Session 2 " );
            s2.Reload(user2);
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));

            txtResult.Text 
=  sb.ToString();

 

 

输出的结果:

[Session 1] User's Name : UserName

[Session 2] User's Name : UserName


Change user's name in Session 1

[Session 1] User's Name : New UserName

[Session 2] User's Name : UserName


Create / Read something else(XpoRole) in Session 2

Role name : RoleName

[Session 1] User's Name : New UserName

[Session 2] User's Name : UserName


Create / Read another XpoUser in Session 2

Another user's name : Another User

[Session 1] User's Name : New UserName

[Session 2] User's Name : UserName


Try to Save the user in Session 2, which is modified in Session 1

Cannot persist the object. It was modified or deleted (purged) by another application.

[Session 1] User's Name : New UserName

[Session 2] User's Name : UserName


Session.Reload(User) in Session 2

[Session 1] User's Name : New UserName

[Session 2] User's Name : New UserName

 

可以看到:

2个不同Session里Load同一个object,确实是同一个object被传递给了2个Session,而并非该Object的任何副本。

在一个Session中对该Object做了修改后,其他Session除非Reload该对象,否则将永远无法获得其他Session对其做的改动。

同时,试图保存这个已经被其他Session所更改过的对象时会抛错。

 

测试2:

ExpandedBlockStart.gif Test2
            ClearDB();
            StringBuilder sb 
=   new  StringBuilder();
            Session s1 
=   new  Session();
            Session s2 
=   new  Session();
            XpoUser user1 
=   new  XpoUser(s1) { Name  =   " UserName "  };
            XpoOrder order 
=   new  XpoOrder(s1) { OrderID  =   " #1 " , User  =  user1 };
            user1.Orders.Add(order);
            user1.Save();
            XpoUser user2 
=  s2.FindObject < XpoUser > ( new  BinaryOperator( " Name " " UserName " ));

            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Order : {0} " , GetOrders(user1)));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Order : {0} " , GetOrders(user2)));


            sb.AppendLine(Environment.NewLine 
+   " Create a new order , change user's name and change Order1's ID to #3 in Session 1 " );
            order 
=  s1.FindObject < XpoOrder > ( new  BinaryOperator( " OrderID " " #1 " ));
            order.OrderID 
=   " #3 " ;
            order.Save();
            order 
=   new  XpoOrder(s1) { OrderID  =   " #2 " , User  =  user1 };
            order.Save();
            user1.Name 
=   " New UserName " ;
            user1.Orders.Add(order);
            user1.Save();
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Order : {0} " , GetOrders(user1)));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Order : {0} " , GetOrders(user2)));

            sb.AppendLine(Environment.NewLine 
+   " Session.Reload(User) in Session 2 " );
            s2.Reload(user2);
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Order : {0} " , GetOrders(user1)));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Order : {0} " , GetOrders(user2)));

            sb.AppendLine(Environment.NewLine 
+   " Session.Reload(User, forceAggregatesReload) in Session 2 " );
            s2.Reload(user2, 
true );
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Order : {0} " , GetOrders(user1)));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Order : {0} " , GetOrders(user2)));

            sb.AppendLine(Environment.NewLine 
+   " Load Order again in Session 2 " );
            order 
=  s2.FindObject < XpoOrder > ( new  BinaryOperator( " OrderID " " #3 " ));
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Order : {0} " , GetOrders(user1)));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Order : {0} " , GetOrders(user2)));

            sb.AppendLine(Environment.NewLine 
+   " Session.Reload(Order, forceAggregatesReload) in Session 2 " );
            s2.Reload(order, 
true );
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Order : {0} " , GetOrders(user1)));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Order : {0} " , GetOrders(user2)));

            sb.AppendLine(Environment.NewLine 
+   " Load Order2 in Session 2 " );
            order 
=  s2.FindObject < XpoOrder > ( new  BinaryOperator( " OrderID " " #2 " ));
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Order : {0} " , GetOrders(user1)));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Order : {0} " , GetOrders(user2)));

            sb.AppendLine(Environment.NewLine 
+   " Session.Reload(Order2, forceAggregatesReload) in Session 2 " );
            s2.Reload(order, 
true );
            sb.AppendLine(
string .Format( " [Session 1] User's Name : {0} " , user1.Name));
            sb.AppendLine(
string .Format( " [Session 1] User's Order : {0} " , GetOrders(user1)));
            sb.AppendLine(
string .Format( " [Session 2] User's Name : {0} " , user2.Name));
            sb.AppendLine(
string .Format( " [Session 2] User's Order : {0} " , GetOrders(user2)));

            txtResult.Text 
=  sb.ToString();

 

 

上面代码其实测试了几种不同的情况,分别注释掉后部几个代码块单独跑可以看得更清楚,这里只贴全部跑的结果:

[Session 1] User's Name : UserName

[Session 1] User's Order : #1 

[Session 2] User's Name : UserName

[Session 2] User's Order : #1 


Create a new order , change user's name and change Order1's ID to #3 in Session 1

[Session 1] User's Name : New UserName

[Session 1] User's Order : #3 #2 

[Session 2] User's Name : UserName

[Session 2] User's Order : #1 


Session.Reload(User) in Session 2

[Session 1] User's Name : New UserName

[Session 1] User's Order : #3 #2 

[Session 2] User's Name : New UserName

[Session 2] User's Order : #1 


Session.Reload(User, forceAggregatesReload) in Session 2

[Session 1] User's Name : New UserName

[Session 1] User's Order : #3 #2 

[Session 2] User's Name : New UserName

[Session 2] User's Order : #1 


Load Order again in Session 2

[Session 1] User's Name : New UserName

[Session 1] User's Order : #3 #2 

[Session 2] User's Name : New UserName

[Session 2] User's Order : #3 


Session.Reload(Order, forceAggregatesReload) in Session 2

[Session 1] User's Name : New UserName

[Session 1] User's Order : #3 #2 

[Session 2] User's Name : New UserName

[Session 2] User's Order : #3 


Load Order2 in Session 2

[Session 1] User's Name : New UserName

[Session 1] User's Order : #3 #2 

[Session 2] User's Name : New UserName

[Session 2] User's Order : #3 #2 


Session.Reload(Order2, forceAggregatesReload) in Session 2

[Session 1] User's Name : New UserName

[Session 1] User's Order : #3 #2 

[Session 2] User's Name : New UserName

[Session 2] User's Order : #3 #2 

 

 

在这个例子里,刷新User没有获得Order的变更,刷新Order也没有获得User的变更,更没有获得同一个User下其他Order的变更。

对于有一对多关系的结构来说,无论是刷新哪个对象,用不用forceAggregatesReload,都只会刷新到自己,不会对关联对象做出更新。

是bug还是对forceAggregatesReload的理解有误?


 

另一个问题是,在Session下并没有找到DropCache()方法,只有一个DropIdentityMap()方法,而调用这个方法以后,再Reload其他对象会抛错(对象已被Dispose)。在DevExpress的官网上大概搜了一下,也没找到什么说法。

 


从上面的测试结果来看,我很同意DevExpress建议的,对每一组互相关联的少量数据都使用一个单独的Session,“大方”的使用。在保持数据之间的逻辑关系不会被破坏的情况下,颗粒度越小越好。 单一Session里包含的数据越少,则这些数据的时间跨度就越小,而且一般说来也越快会被更新。如果想彻底抛弃一个Session的缓存重新加载的话,最好就直接new一个Session来做,而不要去Drop什么的了。

 

 

 

 

转载于:https://www.cnblogs.com/Elvin/archive/2010/02/11/1667599.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值