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


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

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

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

    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");
                }
            }
        }
    }
    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);
                }
            }
        }
    }

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

    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:

    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什么的了。

  • 相关阅读:
    在庫購買管理(MM)
    指図ステータス
    購買発注変更、照会画面に初期表示される発注伝票はどのように決まっているのか
    金額処理
    翻訳
    mysql 与mongodb的特点与优劣
    PHP经典算法
    Linux下PHP安装redis扩展
    Linux上安装Redis教程
    PHP插入法排序
  • 原文地址:https://www.cnblogs.com/Elvin/p/1667599.html
Copyright © 2020-2023  润新知