zoukankan      html  css  js  c++  java
  • 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什么的了。

  • 相关阅读:
    Redis 3.0 与 3.2 配置文件变化
    PHP 位运算(&, |, ^, ~, <<, >>)及 PHP错误级别报告设置(error_reporting) 详解
    MySQL自增ID 起始值 修改方法
    CentOS 6.5 编译 PHP-7 报错:undefined reference to `libiconv_open 无法编译 PHP libiconv
    file xxx from install of xxx conflicts with file from xxx
    专家访谈 / 架构分享 / 网摘 收藏
    怎样用javascript获取UUID
    ansible经常使用模块使用方法
    一个button导致的慘案
    nil coalescing operator
  • 原文地址:https://www.cnblogs.com/Elvin/p/1667599.html
Copyright © 2011-2022 走看看