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

论坛 期权论坛 脚本     
已经匿名di用户   2022-7-2 21:57   1854   0

之前整理了一下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

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP