XPO学习

来源:互联网 发布:西安软件新城二期商铺 编辑:程序博客网 时间:2024/05/22 17:28
 

XPO

这是我从网站上得到的资料,后边是我在使用XPO时所用到的一些知识,包括

XPLiteObject的AutoSaveOnEndEdit属性

ContainsOperator的使用

XPCollection复杂查询

XPView可以增加属性

XPQuery的用法

UnitOfWork的FindObject的用法

Session.Evaluate的计算功能

 

基本概念

   普通类:就是一个简单的定义的类。

   持久化类:可以把类的实例中的数据透时的保存到数据库中的类。

什么是XPO

  XPO是由大名鼎鼎的DevExpress提供的一种商业的ORM工具。

 从概念上来说XPO是一种简单的对象映射技术,是一种把一个普通类变成持久化类的技术。也就是让一个普通的类和数据库中的一个表对应。把表中的字段和类中的字段对应,你可以透明的将一条记录直接保存到数据库,而不需要和ADO.net打交道。

  下面是XPO中的类层次结构

这些类到底有啥作用呢?

这些类提供了将一个类的自身的数据保存到数据库中的所有功能。只要你继承其中一个类,你的类就马上变成了一个可以持久化的类了。也就是具有了将类自己的数据保存到数据库的能力。

看看顶层的XPBaseObject对象,他是XPO持久类中的基类,为其它的类提供了一个基本实现。当你的类继承XPBaseObject,你必须为你的类指定一个主键的字段。他不支持延后删除技术。

XPLiteObject 基本和基类没什么区别 但是他不支持数据库并发中的锁定,和延后删除的技术。

XPCustomeObject 和基类一样,但是他支持并发数据库中的锁定,同时他也和基类要提供自定义主键的。他是支持延后删除技术)

XPObject 这个应该是最常用的,他提供自已的OID字段,因而如果你的类继承于它,就不需要为提供主键。(最全的类了,支持延后删除,支持锁定)

什么叫延后删除:一个持久化类,他是和数据库中的一个记录对应的,当你执行一个删除一个持久化类的动作的时候,XPO不会马上就去在数据库上执行真正的数据删除,而是将这条记录标记为删除,而且已经后不会在读取他。。当你要真正删除时,可以调用Session.PurgeDeletedObjects()来完全删除这些标记的记录

 

 

 

类名

延后删除

数据锁定

提供OID字段

XPBaseObject

不支持

支持

不提供

XPLiteObject

不支持

不支持

不提供

XPCustomObject

支持

支持

不提供

XPObject

支持

支持

提供

 

XPO复合主键

You need to create a struct (Structure in VB.NET), which represents a multi-column key and anXPBaseObject derived class with a Key property definition. Here is the code for mapping to the Sales table in the MS SQL Pubs sample database:

using DevExpress.Xpo;

public struct SalesKey {
    [Persistent("stor_id")]
    public string StorId;
    [Persistent("ord_num")]
    public string OrdNum;
    [Persistent("title_id")]
    public string TitleId;
}

[MapTo("sales"), OptimisticLocking(false)]
public class Sales : XPBaseObject {
    [Key, Persistent]
    public SalesKey Key;

    [Persistent("payterms")]
    public string PayTerms;
    ... // other properties
}

 

 

 

 

 

 

C#中自定义属性的例子

自定义属性的作用

      有时候我们需要给一个类或者类中的成员加上一些属性或者附加信息,让类或者变量的功能更明确可控制的细粒度更高,打个简单的比方:数据库里面的一张表,表中的每一个字段都有很多属性,如是否主键,默认值,注释信息等等,我们在编写实体类的时候,如何表示这些信息呢?通过自定义属性可以实现。

自定义属性的实现步骤

      我说了不算,权威说了算:

1.       声明一个类,并将 AttributeUsageAttribute 属性应用到该类中。类的名称即为新属性的名称

2.       声明该类从 System.Attribute 继承:

3.       定义 Private 字段来存储属性值:

4.       需要时,请为属性创建构造函数:

5.       为属性 (Attribute) 定义方法、字段和属性 (Property):

 实例一个:

属性类(和相关枚举)

/// <summary>
$yQ/S2?g0    /// 数据库字段的用途。ITPUB个人空间 }R h­r P'VB
    /// </summary>
E#j i#Y | Wuf0    public enum EnumDBFieldUsageITPUB个人空间(X­z-w8i&L5zd\0b Jt?
    {
)K­W"l}$Xl0        /// <summary>ITPUB个人空间(O:H i)G.R
        /// 未定义。ITPUB个人空间1K G­v)P]tjqq
        /// </summary>
Q}`)m Ie8k1\;[,^0        None = 0x00,
­_/uZ


`S1_0        /// <summary>
2v^|t l$K&f
z0        /// 用于主键。ITPUB个人空间
eG:u3`!K3n;B4W
        /// </summary>ITPUB个人空间4u-Y%WW!Pb
        PrimaryKey = 0x01,ITPUB个人空间E5DA#fE7V|‑u!b
        /// <summary>ITPUB个人空间WZ}g0aG­q[1]m\0t
F­`
        /// 用于唯一键。ITPUB个人空间"v }‑u;D4[ z8P e9PS2N
        /// </summary>
/k uVS!u't‑X4b$j
l0        UniqueKey = 0x02,ITPUB个人空间g9xM7F_i
        /// <summary>
Y r9Q8MVu0        /// 由系统控制该字段的值。ITPUB个人空间fD:D1| U
        /// </summary>
uY ]0T5nV‑B"^0        BySystem = 0x04

^vpAV
Q#u0    }
/d‑i/@7Cp ||!Al0ITPUB个人空间$R.h8]%_0Pk U
    [AttributeUsage(AttributeTargets.Property, Inherited = true)]
K/p^!@[1]_/jLd5C0    public class DBFieldAttribute:Attribute
i h-fN'T
{!l zn
M0    {
qF H oZ1j0        EnumDBFieldUsage m_usage;
H I-Yi'l0        string m_strFieldName;ITPUB个人空间‑sO;ex;ns-^4u
        string m_strDescription;
Wx6K O
k2\.G0        object m_defaultValue;ITPUB个人空间k:~d)d{Mw'?
}
ITPUB个人空间J |$@{"ZHix
        public DBFieldAttribute(string strFieldName,object defaultValue,EnumDBFieldUsage usage,string strDescription)
"f.z
Ms@"Fk[1]@0        {ITPUB个人空间 T3c.WV!z!{2s+U8t
            m_strFieldName = strFieldName;

F$E`n$}d0            m_defaultValue = defaultValue;
‑|'Q2l5{)G]1h:]­Nk"z}0            m_usage = usage;ITPUB个人空间)}Lo;i2k
            m_strDescription = strDescription;
z‑n~%F
j*C.AZ0        }
[jU P&qg:h
]u0T0
Gh _(eLr0        public DBFieldAttribute(string fieldName) : this(fieldName,null, EnumDBFieldUsage.None,null)
Yq&\a9M‑RQ0        { }ITPUB个人空间 ]9{@_(G
ITPUB个人空间x]7^H!B)H-Y
        public DBFieldAttribute(string fieldName, EnumDBFieldUsage usage) : this(fieldName, null,usage, null)ITPUB个人空间 Nd­b ^3}H)S
        { }
5ti\$WX Kn0
]1I HJ f"ZC‑I0        
#I"UzLi h1c6QHy0        // 获取该成员映射的数据库字段名称。ITPUB个人空间M:S"n I
a*H
x!t
        public string FieldNameITPUB个人空间O
Wc$r@ [Re"T
        {ITPUB个人空间dY
I1cv
Z
}
            get
V$P7L&]Y!N0            {ITPUB个人空间7r7{4CE7n-Ga
                return m_strFieldName;ITPUB个人空间 {(a}8v;sp
            }ITPUB个人空间 z|"ZA;e*b
            set
Z3X/b)aG*GcB p0            {
1i1q:@&D-p
j.xhJ!O
?3]0                m_strFieldName = value;

v­| P7?:j&v9f,{0            }
?
g"U‑C%I6~k5EL0        }
%M
i)p4X^ f.G0ITPUB个人空间 Pq*g+fi b
        // 获取该字段的默认值
2B8Ab+f[1]N2A[1]| ] m0        public object DefaultValue
!Wo;G7dc0        {
_/@%L"s"d(\%`,O0            getITPUB个人空间9I­M w | a Vz1o+^D
            {
­Js&{O1t:w#T x D ?*@0                return m_defaultValue;
*W+y&L Ui$ZL'COs&v0            }ITPUB个人空间@L)V‑z#rY0I1S
            set 
(u‑w*X+`I%Q |0            {ITPUB个人空间:L
@0hgnej
                m_defaultValue = value;
-vM9y[1]a8C;H
D Vj0            }ITPUB个人空间#D+S9he*ic:o'S(H
        }
N @ ]5Tnf0    }

此代码说明了如何制作自定义属性类。其实跟一般的类的区别就是此类继承自Attribute,加上AttributeUsage是属性上的属性,是可选的。

 

数据访问层实体类:

class DalObj
N;x%k


A^0Mb+@0    {
0]/U‑o1a0er0        string m_strTableName;
ctRDta0        int m_nID;ITPUB个人空间i[1]Yh~ y t)Q e!Y
        string m_strName;
E5b K,HI.N!~!]#g#C0        string m_password;
4{(T(k
C%vOw0ITPUB个人空间I V,|b)Dc"D.J
        public DalObj(string strTableName)
D`A U ckC0        {ITPUB个人空间vPF}P
I
            m_strTableName = strTableName;
CQ'Q3ki5X0        }ITPUB个人空间5b.p‑~#i+O

8m `x;O%a0        [DBField("id",EnumDBFieldUsage.PrimaryKey)]ITPUB个人空间 k4f[1]l,S0H C1AE
        public int ID
,j?%y C!v t-BTO8r0        {
E$q2Z M@)WL7d8b }0            get { return m_nID; }ITPUB个人空间0E‑UF[1]AG
Yyx*h
            set { m_nID = value; }
)e7s5v(J5o­B E0        }ITPUB个人空间.X J4L&d:o)G7P5R2?

;M(p|d9j0        [DBField("name",DefaultValue="游客")]
Ao]7N!z R#V2]‑a0        public string NameITPUB个人空间#yT#E+n l-uG:ODR r*}‑b
        {ITPUB个人空间 N$q|
W)i0D
Q:T5x#z&G
            get { return m_strName; }
x)b/t w K2DDI'J Cv*T0            set { m_strName = value; }ITPUB个人空间.B
VrcQ2|
        }ITPUB个人空间wd0NF/m `

.\@­Zf[1]~q0        [DBField("pwd")]ITPUB个人空间q%c4K [$sx
v[1]X
        public string PassWordITPUB个人空间&g5u1hU5U-v y%H
        {
I7M"R.oqt-u0            get { return m_password; }ITPUB个人空间FWk@M Z
            set { m_password = value; }ITPUB个人空间-n0C5~/S)}4`t9kps
        }ITPUB个人空间[1][^ _
^"hS
    }

 

此代码说明了如何使用自定义的属性。有两点需要注意的地方

第一:类名可以跟自定义的类名一样,也可以加上或减去后面的Attribute,本例子中就是使用的时候跟自定义的类名减少了“Attribute”。

第二:属性参数填写方法,如果自定义属性类(例子中DBFieldAttribute)自己的构造函数带参数,那么这些参数是必选的,可以重载构造函数以满足不同组合,必选参数填完之后,可以继续给自定义属性类中的公共成员带命名地赋值,如例子中的DefaultValue="游客" 一句就是命名参数。

遍历自定义属性的代码:

            DalObj dalObj = new DalObj("users");ITPUB个人空间3?W^1n t#v}
            StringBuilder sb = new StringBuilder();ITPUB个人空间9M3R.^q2xQD


F
            foreach (PropertyInfo proInfo in dalObj.GetType().GetProperties())ITPUB个人空间$X}c
k zh
            {ITPUB个人空间L
c,Qj!B
                object[] attrs = proInfo.GetCustomAttributes(typeof(DBFieldAttribute), true);ITPUB个人空间{­\[1]bo[1]Y4?e‑ZS
              if (attrs.Length == 1)ITPUB个人空间wj1AMs‑^ H
              {ITPUB个人空间4CU8X:E e
T
                  DBFieldAttribute attr = (DBFieldAttribute)attrs[0];ITPUB个人空间%RY N,^,}­ba3_
                  sb.Append(attr.FieldName + ":" + (attr.DefaultValue == null ? "null" : attr.DefaultValue.ToString()) + "\r\n");
EUK3r+` U_0              }ITPUB个人空间&{*_Z-c-@Qw5|
            }ITPUB个人空间v5[*HLJ1A
s;G6Ug
            MessageBox.Show(sb.ToString()); 

此代码说明了如何检索自定义属性的值,主要用到了GetCustomAttributes来获取属性值。

 

 

 

XPO对Attribute的总结:

              应该看到,整个XPO框架中,Attribute使用的相当频繁,可以列出常用的:

            

         [Aggregated]   没有参数

            作用于a property or a field,并且只能是持久类的引用或者XPCollection.

            实现两个持久类的级联删除的功能。

       

[Association("PersonAddresses", typeof (Address))]

    作用于a property or a field

    实现两个持久类的级联关系

    参数:1、关联的名称;2、关联的持久类类型(但引用指明持久类型时,可以省略)

        

         [MapTo("T_Person")]

            作用于持久类或a property or a field

            作用于持久类时:指定持久类映射的表名称。如果没有指定,默认的表名就是类名。

            作用于property或field时:表的列名称。

            参数是表名或列名,是区分大小写的。

       

        [Persistent("CreatedOn")] 强制映射字段

            作用于a property or a field

XPO一般只对持久类中的可写property和public field进行持久化操作。因此对只读的field可以加上该特性进行强制持久化。

参数:表名(可选)

       

[NonPersistent]

            作用于a class, property or a field

                 指明不对类或property,field进行持久化操作。

            参数无。

       

[DbType]

            指定列创建时使用的数据类型。

            参数:字符串的数据类型表示。

   

[MapInheritance(MapInheritanceType.OwnTable)]

            作用于持久类。

            两个持久类是继承关系时,持久信息的存储方式。

            参数:

                MapInheritanceType.OwnTable :各自独立的表,分别存储独有部分。

                MapInheritanceType.ParentTable :都在父表存储。

       

        [Delayed("document")]

            只能作用于Property。

            延迟数据装载,当持久类构造时并不装载数据,只是property首次被访问时才装载。

            和类XPDelayedProperty结合使用才能实现延迟装载的功能。

            参数:引用的XPDelayedProperty 类型field 名称。

 

        [Size(SizeAttribute.Unlimited)] 数据长度

            作用范围a property or a field。

指定映射的表字段长度。只是当创建字段时才体现。当字段已经存在,XPO此时不会检查该值。

            参数:数值的长度或者SizeAttribute.Unlimited(不限制长度)

                  可以不指定。如果是string,默认是100。

           

        [Key ] ,[Key(true)],[Key(AutoGenerate = true)] 

作用于a property or a field。

指定主键。每个持久类都需要一个指定为key的propery or field。XPObject和XPBaseObject的一个明显差别就是XPObject已有一个OId主键

参数:bool型(可选)。是否由XPO自动生成键值(Int或GUID)。默认是false。

       

        [Indexed]

            作用于a property or a field。

                 指定索引。默认情况下改索引是非唯一索引。

            没有构造参数。但可以通过set来设置为唯一索引[Indexed(Unique=true)]

 

        [OptimisticLocking(false)] 

            作用于持久类。

        是否乐观锁定(感谢format 的指错)。如果锁定,修改后提交时,XPO会检查原始数据是否已经被改变,而不是who lastest who win。XPO在持久类映射的表类加一个系统字段“OptimisticLockField”,显然是用来标记状态的。因此如果是映射到视图时,要显式设置为不锁定。

            参数:bool值(可选,默认是true)

 

        [ValueConverter(typeof(实现转换接口(抽象类ValueConverter)的类))] 

            作用于property。

值和类型转换,挺有意思的一个功能。从数据库提取值和保存值都可以作一个转换工作。

       

        [NullValue("")]

            作用于简单数据类型的a property or field。

                 指定对应库中值为null时,持久类中对应的数据。反之也是。

            参数:根据不同的数据类型,引入不同的参数。看例子比较方便:

         public class Example : XPObject {
              [NullValue(Int32.MinValue)]              public int NullOnMinValueFieldInt;                             [NullValue(0)]              public int NullOnZeroFieldInt;
         [NullValue("")]              public string NullOnEmptyStringFieldString;
         [NullValue("NULL")]              public string NullOnNULLFieldString;            }
    

          本想只列出常用的,但看看代码,就差两个就列完了。
      [ExplicitLoading]

[MemberDesignTimeVisibility]

 

Attribute

Description

AggregatedAttribute

Indicates that a property or field references other aggregated persistent objects.

AssociationAttribute

Specifies the association name for the property which represents a relationship between objects.

CustomAttribute

Specifies a custom attribute for a class or member.

DbTypeAttribute

Specifies the database type of the column that a property is mapped to.

DefaultMembersPersistence

Specifies which members are implied as persistent by default.

DeferredDeletionAttribute

Enables deferred object deletion.

DelayedAttribute

Indicates that the property's value should not be loaded when a persistent object is being loaded. The property will be loaded the first time it is accessed.

DisplayNameAttribute

Specifies the member's display name.

ExplicitLoadingAttribute

Specifies that the information used to retrieve persistent objects that are referenced by the current property, is included in a query used to load this property.

IndexedAttribute

Indicates that a property or field participates in index creation.

KeyAttribute

Indicates that a property or field is a key.

MapInheritanceAttribute

Specifies the type of object-relational inheritance mapping for the class.

MemberDesignTimeVisibilityAttribute

Specifies whether a property or class is visible at design time.

NoForeignKeyAttribute

Disables automatic creation of the FOREIGN KEY Constraints.

NonPersistentAttribute

Indicates that a class, property or field will not be stored in a persistent data store.

NullValueAttribute

Associates the constant with the null value of a property or field of the simple type.

OptimisticLockingAttribute

Specifies that a persistent object's state can be locked during a session.

PersistentAliasAttribute

Indicates that a property's value can be evaluated from the persistent fields or stored in a single persistent field.

PersistentAttribute

Indicates that a property, field or class will be stored in a persistent data store.

SizeAttribute

Specifies the maximum number of characters that can be stored in a column which is created to store the data of a property or field.

ValueConverterAttribute

Specifies that a persistent property has a converter for its value.

 

 

 

 

 

 

 

 

 

 

XPO注意事项

1、对二进制大对象字段的存取

    使用延迟装载(Delayed Loading)

       这里必须指定一个私有的XPDelayedProperty类型的属性,并且加上Attribute,设计上有点繁琐。

       public class Customer: XPObject {

        ...

        private XPDelayedProperty document = new XPDelayedProperty();

        [Delayed("document")]

        public Byte[] Attachment {

               get { return (Byte[])document.Value; }

               set { document.Value = value; }

        }

    }

 

2、事务的支持:

事务在数据库程序内是不可或缺的。

显然该功能是由Session提供的。

Account account = new Account();

        Session.DefaultSession.BeginTransaction();

        try {

               account.Amount = amount;

               account.Save();

               Session.DefaultSession.CommitTransaction();

        }

        catch (Exception e) {

               Session.DefaultSession.RollbackTransaction();

               account.Reload();

        }

 

注意在Exception发生时,使用了Reload()。

 

 

3、保存之前的数据有效性检查:

    class Account: XPObject {

            public double Amount = DefaultAmount;

            protected override void BeforeSave() {

                base.BeforeSave();

                if(!IsDeleted) {

                    if (Amount < 0) {

                        throw new Exception("Negative amount");

                    }

                }

            }

        }

    注意先判断了IsDeleted。

 

 

 

 

 

 

XPO 的数据表示

XPObject

 

XPCollection

 

XPView

 

Pageable Collection(XPCursor)

 

Session.GetObjects

 

XPO中查询数据:

对于查询,就是指定一定的条件获取一个数据集合。在XPO中,返回结果的集合用XPCollection作统一处理

 
XPCollection collection = new XPCollection(typeof(Person));
 
XPCollection xpCollectionPerson = new XPCollection(typeof(Person),
CriteriaOperator.Parse("IsMale==false"));

 

XPO中返回记录的分页处理:

在XPO中,除了XPCollection外,还有一个XPCursor提供了一个获取返回记录的另外一种方式。和XPCollection返回全部的满足条件的集合不同,XPCursor根据XPCursor.PageSize的设置依次返回满足条件的每页数据。
 
XPCursor这种特性在处理数据量比较大的表是十分有用的,可以减少每次内存的使用量和减少返回的时间。

当然,每次翻页则需要重新获取数据。

 

取得某个XPObject    Session.GetObjectByKey

gpspatrolforelec20080402.TSitus obj = (gpspatrolforelec20080402.TSitus)xposessoin.GetObjectByKey(typeof(gpspatrolforelec20080402.TSitus), 151);

 

 

 

 

 

 

 

 

Criteria Language Syntax

The criteria language, provided by eXpress Persistent Objects (XPO), is used in queries for persistent objects built using theCriteriaOperator.Parse method. It allows you to query for objects using standard object oriented syntax, and also includes several operators used to compare complex values.

Familiar Visual Basic and C# Syntax

The following examples show identical expressions. The first example is similar to Visual Basic .NET syntax. The second example is similar to C#. The criterion selects persistent objects whoseName property equals "John" or Age property equals 30:

Name = 'John' Or Age = 30

Name == 'John' || Age == 30

Literals

The following table lists the types supported by the XPO criteria language.

Type

Delimiter

Description

DateTime

#

Date and time comparison values.

Enumeration

 

Enumeration comparison values. To specify an enumeration value in criteria, use its name enclosed in apostrophes:

Status = 'InProgress'

If an enumeration value has an initializer, you can use the initializer value:

Status = 1

Note that you cannot specify an enumeration value via its qualified name. So, the following criteria is incorrect:

Status = Status.InProgress

Guid

{}

Guid comparison values. A Guid may only be used in a relational operation with equality or inequality operators.

Numeric

 

Numeric comparison values.

String

'

String comparison values.

Operators

The following tables list available operators.

Aggregation

Operators that perform aggregate operations on collections.

Name

Description

Usage

Avg

Evaluates an average of all values in a collection.

CriteriaOperator.Parse("Accounts.Avg(Amount) = 75")

Count

Returns the number of objects in a collection.

CriteriaOperator.Parse("Accounts.Count > 1")

Exists

Determines whether a collection property marked with the AssociationAttribute contains objects.

CriteriaOperator.Parse("Accounts.Exists")

Max

Returns the maximum expression value in a collection.

CriteriaOperator.Parse("Accounts.Max(Amount) > 75")

Min

Returns the minimum expression value in a collection.

CriteriaOperator.Parse("Accounts.Min(Amount) < 10")

Sum

Returns a sum of all expression values in a collection.

CriteriaOperator.Parse("Accounts.Sum(Amount) > 150")

Binary

Logical expressions that consist of comparison operations between two operands.

Name

Description

Usage

BitwiseAnd

Represents the bitwise AND operator.

CriteriaOperator.Parse("Roles & 1 = 1")

BitwiseOr

Represents the bitwise OR operator.

CriteriaOperator.Parse("Roles | 253 = 255")

BitwiseXor

Represents the bitwise XOR operator.

CriteriaOperator.Parse("Roles ^ 253 = 255")

Divide

Represents the division operator.

CriteriaOperator.Parse("Accounts.Max(Amount) / Accounts.Min(Amount) > 10")

Equal

Represents the Boolean equality operator.

CriteriaOperator.Parse("Name = 'John'")

Greater

Represents the Boolean greater-than operator.

CriteriaOperator.Parse("Age > 20")

GreaterOrEqual

Represents the Boolean greater-than-or-equal-to operator.

CriteriaOperator.Parse("Age >= 20")

Less

Represents the Boolean less-than operator.

CriteriaOperator.Parse("Age < 20")

LessOrEqual

Represents the Boolean less-than-or-equal-to operator.

CriteriaOperator.Parse("Age <= 20")

Like

Represents the LIKE operator that determines whether a specific character string matches a specified pattern.

The following wildcard characters are supported:

·  % matches a string of zero or more characters. For instance:

CriteriaOperator.Parse("Name like 'Jo%'") - returns all the objects whose Name begins with 'Jo'.

CriteriaOperator.Parse("Name like '%car%'") - returns all the objects whose Name contains the 'car' substring.

·  _ matches a single character. For instance:

CriteriaOperator.Parse("Name like 'car_'") - returns all the objects whose Name consists of four characters, and begins with 'car'.

·  [ ] identifies a single character within the specified range ([a-c]) or set ([abc]). For instance:

CriteriaOperator.Parse("Name like '[A-C]%'") - returns all the objects whose Name begins with 'A', 'B' or 'C'.

·  [^] excludes a single character not within the specified range ([^a-c]) or set ([^abc]). For instance:

CriteriaOperator.Parse("Name like 're[^de]%'") - returns all the objects whose Name begins with 're', and where the following letter is not 'd' or 'e'.

CriteriaOperator.Parse("Name like 'Jo%' or Name like '%ob'")

Minus

Represents the subtraction operator.

CriteriaOperator.Parse("Age - 30 > 0")

Modulo

Represents the modulus operator (computes the remainder after dividing its first operand by its second).

CriteriaOperator.Parse("Age % 50 = 0")

Multiply

Represents the multiplication operator.

CriteriaOperator.Parse("Accounts.Sum(Amount) * 20 >= 3000")

NotEqual

Represents the Boolean inequality operator.

CriteriaOperator.Parse("Name != 'John'")

Plus

Represents the addition operator.

CriteriaOperator.Parse("Age + 50 = 100")

Function Operators

The table below lists only basic logical and string management operators. For a complete set of available function operators, refer to theFunctionOperatorType enumeration description.

Name

Description

Usage

Concat

Concatenates one or more strings.

CriteriaOperator.Parse("Name like concat ('%J', 'o%')")

Custom

This operator allows you to implement a custom function that is supported by a specific database engine.

To learn more, see the How to: Implement a Custom Criteria Language Operator topic.

CriteriaOperator.Parse("Custom('CustomFunctionName', [Property], 'Value', ...)")

Where CustomFunctionName is a mandatory parameter followed by the custom function's parameters.

Iif

Returns one of two values depending upon the value of a logical expression.

The function requires three operands of the CriteriaOperator class:

1 - determines the logical expression;

2 - specifies the value that will be returned if the logical expression evaluates totrue;

3 - specifies the value that will be returned if the logical expression evaluates tofalse.

CriteriaOperator.Parse("(Iif (Accounts.Sum(Amount) > 150, 1, 0) = 1)")

IsNull

Compares the first operand with the null value. This function requires one or two operands of theCriteriaOperator class.

The value returned depends upon the number of arguments.

If a single argument is passed, the function returns true if the operand isnull, otherwise, false is returned.

If two operands are passed, the function returns the second operand if the first operand isnull, otherwise, the first operand is returned.

CriteriaOperator.Parse("isnull(Name)")

Len

Returns the length of the string specified by an operand.

The operand should be an object of the CriteriaOperator type.

CriteriaOperator.Parse("Len(Name) > 3")

Lower

Converts all characters in a string operand to lowercase.

The operand should be an object of the CriteriaOperator type.

CriteriaOperator.Parse("Lower(Name) like '%jo%'")

Substring

Returns a substring extracted from the specified string. This function requires two or three operands of theCriteriaOperator class.

If two operands are passed the substring will be extracted from the beginning of the original string. The operands should be defined as follows:

1 - an original string;

2 - an integer that specifies the length of the substring.

If three operands are passed, a substring can be subtracted starting from any position in the original string. The operands should be defined as follows:

1 - an original string;

2 - an integer that specifies the zero-based index at which the substring to return begins;

3 - an integer that specifies the length of the substring.

CriteriaOperator.Parse("Substring(Name, 0, 2) = 'Bo'")

Trim

Returns a string containing a copy of a specified string with no leading or trailing spaces.

This function requires a single operand of the CriteriaOperator class that refers to the original string.

CriteriaOperator.Parse("Trim(Name) = 'Bob'")

Upper

Converts all characters in a string operand to uppercase.

The operand should be an object of the CriteriaOperator type.

CriteriaOperator.Parse("Upper(Name) like '%JO%'")

Group

Logical expressions which group two or more operands with a logical AND or OR.

Name

Description

Usage

And

Groups operands with logical AND.

CriteriaOperator.Parse("Name = 'John' and Age = 30")

Or

Groups operands with logical OR.

CriteriaOperator.Parse("Name = 'John' or Age = 30")

Unary

Unary operators which perform operations on a single expression.

Name

Description

Usage

BitwiseNot

Represents the bitwise NOT operator.

CriteriaOperator.Parse("~Roles = 251")

IsNull

Represents the operator which determines whether or not a given expression is NULL.

CriteriaOperator.Parse("Name is null")

Minus

Represents the unary negation (-) operator.

CriteriaOperator.Parse("-Age = -20")

Not

Represents the logical NOT.

CriteriaOperator.Parse("not (Name = 'John' or Age = 30)")

Plus

Represents the unary plus (+) operator.

CriteriaOperator.Parse("Age = +10")

Miscellaneous

Name

Description

Usage

Between

Determines whether the expression lies between the specified range of values.

CriteriaOperator.Parse("Age between (20, 40)")

In

Determines whether a value matches any value in the specified list.

CriteriaOperator.Parse("Name in ('John', 'Bob', 'Nick')")

Related Property Reference

To refer to a related property, use brackets "[ ]". For instance, the following query returns all persistent objects that have an Account with an Amount of 100:

Accounts[Amount == 100]

Grouping Clauses with Brackets

When a query traverses an object relationship, the XPO architecture ensures that a related object exists before comparing property values. Because of this behavior, it is important to use brackets to ensure that your query returns the intended results.

For instance, the following query for objects of Customer type returns all of the customers where an Account exists with a Date of 8/25/2006 and where an account exists with an Amount of 100:

Accounts[Date == #8/25/2006#] && Accounts[Amount == 100]

To search for all customers that have an Account with both a Date of 8/25/2006 and an Amount of 100, construct the query as in the following example:

Accounts[Date == #8/25/2006# && Amount == 100]

Parent Relationship Traversal Operator

The '^' character is used to refer to the parent in a parent-child relationship. The parent relationship traversal operator allows you to access parent objects in expressions written in the context of a child. The parent operator can be applied successively to navigate multiple parent relationships. Consider the following expression:

C#

Copy Code

XPCollection<Customer> Customers = new XPCollection<Customer>();

Customers.Criteria = CriteriaOperator.Parse("Orders[^.RegistrationDate == Date]");

Visual Basic

Copy Code

Dim Customers As XPCollection(Of Customer) = New XPCollection(Of Customer)()

Customers.Criteria = CriteriaOperator.Parse("Orders[^.RegistrationDate == Date]")

Here, the "RegistrationDate" property refers to the Customer objects and the "Date" property refers to the Order objects. This expression selects all the customers who have made at least one order on the day they registered. The parent relationship traversal operator can only be used within brackets in the context of the ContainsOperator. So, the following expression is incorrect:

C#

Copy Code

XPCollection<Order> Orders = new XPCollection<Order>();

Orders.Criteria = CriteriaOperator.Parse("^.RegistrationDate == Date");

Visual Basic

Copy Code

Dim Orders As XPCollection(Of Order) = New XPCollection(Of Order)()

Orders.Criteria = CriteriaOperator.Parse("^.RegistrationDate == Date")

Operator Precedence

When an expression contains multiple operators, operator precedence controls the order in which the elements of the expression are evaluated.

·                         Literal values

·                         Parameters

·                         Identifiers

·                         OR (left-associative)

·                         AND (left-associative)

·                         '.' relationship qualifier (left-associative)

·                         ==, !=, Like

·                         <, >, <=, >=

·                         -, + (left-associative)

·                         *, /, % (left-associative)

·                         NOT

·                         unary -

·                         In

·                         Iif

·                         Trim(), Len(), Substring(), IsNull()

·                         '[]' (for set-restriction)

·                         '()'

The default precedence can be changed by grouping elements with parentheses. For instance, in the first of the following two code samples, the operators will be performed in the default order. In the second code sample, the addition operation will be performed first, because its associated elements are grouped with parentheses, and the multiplication operation will be performed last:

Accounts[Amount == 2 + 48 * 2]

Accounts[Amount == (2 + 48) * 2]

Case Sensitivity

Operators are case insensitive. The case sensitivity of values depends on the data source.

Note

The behavior of certain operators is affected by the data source. For instance, by default, SQL Server Express 2005 is configured as case insensitive. In this case, the following expression always evaluates totrue, and all persistent objects are selected:

Lower(Name) == Upper(Name)

Upcasting

The upcasting feature allows you to access properties of a class different from a collection's base class. This feature is useful if you have a collection typed for a base class, and in reality it holds objects of a derived class. Since this collection is typed for the base class, you are only able to directly access its properties. To access the properties of the derived class, they must be upcasted.

The following code snippet demonstrates this. The ExtendedProperty is upcasted in the second line to specify that it is a property of the CustomClass derived from the CustomBaseClass:

C#

Copy Code

XPCollection<CustomBaseClass> myCollection = new XPCollection<CustomBaseClass>(session);

CriteriaOperator filterOperator = CriteriaOperator.Parse("<CustomClass>ExtendedProperty > 0");

myCollection.Filter = filterOperator;

Visual Basic

Copy Code

Dim myCollection As XPCollection(Of CustomBaseClass) = New XPCollection(Of CustomBaseClass)(session)

Dim filterOperator As CriteriaOperator = CriteriaOperator.Parse("<CustomClass>ExtendedProperty > 0")

myCollection.Filter = filterOperator

Escaping Keywords

If the property name of an object is also a keyword, then you can escape the property name by prefixing it with an @ sign. For instance, in the@Or = 'value' query, the CriteriaOperator.Parse method interprets @Or as the property named "Or", not the logical operator OR

定义

CriteriaOperator criteria = new BinaryOperator(

    new OperandProperty("City"), new OperandValue("Chicago"),

    BinaryOperatorType.NotEqual

);

CriteriaOperator criteria = CriteriaOperator.Parse("City != 'Chicago'");

 

// Retrieves a collection of the Contact objects which match the criteria that represents

// the logical expression (DefaultAddress.City <> "Chicago").

XPCollection collection = new XPCollection(typeof(Contact),

    CriteriaOperator.Parse("DefaultAddress.City != 'Chicago'")

);

 

 

 

 

 

 

 

 

 

XPO 使用记录

1. 一般实体类直接继承自 XPObject,如果需要自定义主键或自增字段则可继承自XPCustomObject。

 

2. 继承自XPBaseObject的实体类,Delete后将被直接物理删除。而XPCustomObject & XPObject的继承类则是软删除。

  (1) 实体对象软删除

  customer.Delete();

  customer.Save();

 

  (2) 物理删除

  Session.DefaultSession.PurgeObject(customer);

 

  (3) 物理删除所有被标记软删除的记录。

  Session.DefaultSession.PurgeDeletedObjects();

 

  (4) 清除数据库中所有数据。

  Session.DefaultSession.ClearDatabase();

 

  (5) 恢复被软删除的记录。

  while(true)

  {

    o = (MyObject)Session.DefaultSession.FindObject(typeof(MyObject), new NotOperator(new NullOperator("GCRecord")), true);

    if (o == null)

    {

      break;

    }

    o.GCRecord = null;

    o.Save();

  } 

 

  (6) 批量删除

 

  XPCollection customers = new XPCollection(typeof(Product), new BinaryOperator("Customer", "Tom"));

  Session.DefaultSession.Delete(customers);

  Session.DefaultSession.Save(customers);

 

7)直接通过传SQL语句获得对象集合的方法!


  Dim command As IDbCommand
        Dim reader As IDataReader
        command = DevExpress.Xpo.Session.DefaultSession.ConnectionProvider.CreateCommand()
        command.CommandText = "Select * from VS_Service where F0302=2" 
        reader = command.ExecuteReader()

        DataGrid1.DataSource = reader
        DataGrid1.DataBind()
        reader.Close()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

使用XPO连接高于5.2.5.0版本的MySQL

 

XPO自然是支持MySQL的,只需要在项目里添加对MySql.Data的DLL(从MySQL官网下载Connector/Net可得)和DevExpress.Xpo.v9.2.Providers的DLL引用,并且在项目的入口点构造XpoDataLayer时指定使用MySQL即可。

  然而测试时遇到问题。手里的9.2.10版本的XPO,在编译时使用的是5.2.5.0版本的MySQL,而下载到的最新的是6.2.2.0,不能用。

  这时我们可以修改并重新编译XPO的源代码,但我想没人高兴这么做。

  还有个简单的办法,即在Config文件中添加如下代码:

<?xml version="1.0"?> 
<configuration> 
    <runtime> 
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
            <dependentAssembly> 
                <assemblyIdentity name="MySql.Data" publicKeyToken="c5687fc88969c44d" culture="neutral"/> 
                <bindingRedirect oldVersion="5.2.5.0" newVersion="6.2.2.0"/> 
            </dependentAssembly> 
        </assemblyBinding> 
    </runtime> 
</configuration>

  指定好oldVersion和newVersion即可。

 

 

 

 

 

 

 

 

搜集XPO (eXpress Persistent Objects) 学习资料


from:http://goody9807.cnblogs.com/

1.绑定一般的DropDownList
     
       M_ReferringAgentAndGP是一个对应数据库表的实体类,
       M0201是要显示的文本,M0200要显示的文本对应的值域

       Dim Agent As XPCollection = New XPCollection(GetType(M_ReferringAgentAndGP))
       ddlF1609.DataSource = Agent
       ddlF1609.DataTextField = "M0201"
       ddlF1609.DataValueField = "M0200"
       ddlF1609.DataBind()


2.绑定有组合字段的DropDownList

       M_StaffDetails类中有M0000,M0002,M0003字段域,分别对应主鍵,FirstName,LastName
       Dim sName As XPCollection = New XPCollection(GetType(M_StaffDetails))
       ddlF1617.DataSource = sName
       ddlF1617.DataTextField = "FullName"
       ddlF1617.DataValueField = "M0000"
       ddlF1617.DataBind()

在M_StaffDetails类中加入如下属性:
<Persistent()> _
   Public ReadOnly Property FullName() As String
       Get
           Return String.Format("{ 0 } { 1 }", M0002, M0003)
       End Get
   End Property

在生成数据库时会把FullName当作一个字段创建出来


3.通过主鍵获得唯一一条记录

  F_DomesticViolence是对应数据库中的一个表的类,ID是这个表的主鍵


       Dim bizObject As New F_DomesticViolence
       Dim newSession As New DevExpress.Xpo.Session
       newSession.ConnectionString = DevExpress.Xpo.Session.DefaultSession.ConnectionString
       bizObject = newSession.GetObjectByKey(GetType(F_DomesticViolence), CStr(ID))


4.新增和保存一条记录


加重显示的地方是关键,开始没这样写,导致每次操作都是新增数据,后来想到由于是持久性对象,所以
只要不释放,它一直都存在,如果每次都 Dim bizObject As New ... ,那么每点保存按钮时,重新建立一个对象

所以导致每次都是新增数据,要想保存必须找到以前的持久性对象,所以用了如下方法!


Dim bizObject As New F_DomesticViolence
       If Request.QueryString("mode") = "edit" Then
           bizObject = New XPCollection(GetType(F_DomesticViolence), New BinaryOperator("F1600", editID, BinaryOperatorType.Equal)).Object(0)
       End If

       With bizObject

           .F1601 = chkF1601.Checked
           .F1602 = chkF1602.Checked
           .F1603 = chkF1603.Checked
           .F1604 = chkF1604.Checked
           .F1605 = ddlF1605.SelectedValue
           .F1606 = chkF1606.Checked
           .F1607 = chkF1607.Checked
           .F1608 = chkF1608.Checked
           .F1609 = ddlF1609.SelectedValue
           .F1610 = txtF1610.Text
           .F1611 = txtF1611.Text

           .F1613 = chkF1613.Checked
           .F1614 = chkF1614.Checked
           .F1615 = chkF1615.Checked
           .F1616 = txtF1616.Text
           .F1617 = ddlF1617.SelectedValue
           .F1618 = saveDateNull(txtF1618)
           .F1619 = txtF1619.Text


           'If Request.QueryString("mode") = "edit" Then
           '.F1600 = 9
           'End If

           .Save()
       End With


5.多条件查询,返回对象集合!
       
      加重显示的语句可以增加多个条件

      Dim cond As New GroupOperator
       Dim oper1 As New BinaryOperator(New OperandProperty("F1400"), New OperandValue(2), BinaryOperatorType.Greater)
       Dim oper2 As New BinaryOperator(New OperandProperty("F1401"), New OperandValue(1), BinaryOperatorType.Equal)
       cond = New GroupOperator(GroupOperatorType.And, oper1, oper2)
       Dim Collection1 As New XPCollection(GetType(F_ExitInterview), cond)
       DataGrid1.DataSource = Collection1
       DataGrid1.DataBind()
6.表关系为一对多的实现方法.

[Aggregated]   没有参数      

             实现两个持久类的级联删除的功能,简单地说就是如果加上Aggregated参数,那么删除主表的时记录时一同连子表的记录也都删除了,如果不加那么必须把子表的数据全部删除才可以删除主表的记录.

例子:

有一个主表 V_CommonReview  和一个子表V_Exit
主表V_CommonReview  主键为V0900  
子表V_Exit  主键为V0600 外鍵为V0627

一条V_CommonReview表中记录对应多条子表V_Exit的记录

那么为了实现级联关系那么先在子表V_Exit定义一个外鍵为V0627
类型为V_CommonReview对象类型.

<Association("V_ExitCommonReview")> Public V0627 As V_CommonReview


然后在V_CommonReview表中定义


<Association("V_ExitCommonReview", GetType(V_Exit))> _
   Public ReadOnly Property V_exits() As XPCollection
       Get
           Return GetCollection("V_exits")
       End Get
   End Property


注:V_ExitCommonReview为关系名称,起什么都可以


做完这步了就可以把子表当作一个数据库中的视图显示两个表中的记录了

例如:

(1)  下面是实现关联表数据集合的显示功能.

Dim x As New XPCollection(GetType(V_Exit))
       x.DisplayableProperties = "V0627.V0900;V0627.V0901;V0627.V0902"
       DataGrid1.DataSource = x
       DataGrid1.DataBind()

默认情况下如果设置DataGrid的自动生成列属性为真,那么把子表的内容全都显示出来,但你可以通过设置XPCollection的DisplayableProperties属性来设置想要显示的主表中的字段.


(2) 下面是实现关联表单条数据的增加和保存功能.


 Dim bizObject As V_Exit
       If CheckIsEdit() Then
           bizObject = New XPCollection(GetType(V_Exit), New BinaryOperator("V0602", CInt(Session("VOLUNTEERID")), BinaryOperatorType.Equal)).Object(0)

       Else
           bizObject = New V_Exit
       End If
       With bizObject
           '.V0601 = ddlV0601.SelectedValue
           .V0602 = CInt(Session("VOLUNTEERID"))
           .V0603 = txtV0603.Text
             .......

           If .V0627 Is Nothing Then  '----这里.V0627是一个类对象
               Dim CR As New V_CommonReview

               With CR
                   .V0901 = ddlV0901.SelectedValue
                   .V0919 = txtV0919.Text
                   .V_exits.Add(bizObject)
                   .Save()
               End With
           Else
               .V0627 = New XPCollection(GetType(V_CommonReview), New BinaryOperator("V0900", .V0627.V0900, BinaryOperatorType.Equal)).Object(0)
               .V0627.V0901 = ddlV0901.SelectedValue
                       
               .V0627.V0919 = txtV0919.Text
               .V0627.V_exits.Add(bizObject)
               .Save()
           End If
         
      End With

     
只需保存主表的内容,把子表的域都赋值,那么子表的内容自动保存



(3) 下面是实现关联表单条数据的显示功能.

在Load数据时也要先判断一下外键是否为空,然后在Load主表信息

 Dim bizObject As V_Exit
       If CheckIsEdit() Then
           bizObject = New XPCollection(GetType(V_Exit), New BinaryOperator("V0602", CInt(Session("VOLUNTEERID")), BinaryOperatorType.Equal)).Object(0)

       Else
           Return
       End If

       With bizObject
          txtV0603.Text = .V0603
        If Not .V0627 Is Nothing Then
               ddlV0901.SelectedValue = .V0627.V0901
               ddlV0902.SelectedValue = .V0627.V0902
        End If
       End With



7.直接通过传SQL语句获得对象集合的方法!


 Dim command As IDbCommand
       Dim reader As IDataReader
       command = DevExpress.Xpo.Session.DefaultSession.ConnectionProvider.CreateCommand()
       command.CommandText = "Select * from VS_Service where F0302=2"
       reader = command.ExecuteReader()

       DataGrid1.DataSource = reader
       DataGrid1.DataBind()
       reader.Close()



8.删除一条记录的写法

Dim bizobject As New F_FamilyService
       bizobject = New XPCollection(GetType(F_FamilyService), New

BinaryOperator("F0300", editID,

BinaryOperatorType.Equal)).Object(0)
       bizobject.Delete()

注:F0300为F_FamilyService表的主键

--------------------------------
如何利用反射得到中间层中的所有类(利用XPO来做的项目中的例子)

1.利用反射得到中间层中的所有类生成所有表
Public Shared Function init()
       Dim d As [Assembly] = [Assembly].Load("DAL")
       Dim types As Type() = d.GetTypes()
       Dim t As Type

       DevExpress.Xpo.Session.DefaultSession.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + HttpContext.Current.Server.MapPath("/") + "workdb\FamilyService.mdb;"
       DevExpress.Xpo.Session.DefaultSession.AutoCreateOption = AutoCreateOption.SchemaOnly
       For Each t In types
           Dim obj As New Object
           If t.FullName <> "DAL.InitDataBase" Then
               obj = d.CreateInstance(t.FullName)
               'obj = Activator.CreateInstance(t)
               obj.save()
           End If

       Next
   End Function

2.利用反射得到中间层中的所有类生成所有表(除编码表)

   Public Shared Function initNoCode()
       Dim d As [Assembly] = [Assembly].Load("DAL")
       Dim types As Type() = d.GetTypes()
       Dim t As Type

       'DevExpress.Xpo.Session.DefaultSession.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + HttpContext.Current.Server.MapPath("/") + "workdb\FamilyService.mdb;"
       'DevExpress.Xpo.Session.DefaultSession.AutoCreateOption = AutoCreateOption.SchemaOnly
       'Dim session As New DevExpress.Xpo.Session
       'session.ConnectionString = DevExpress.Xpo.Session.DefaultSession.ConnectionString
       'session.AutoCreateOption = AutoCreateOption.SchemaOnly

       For Each t In types
           Dim obj As New Object

           If t.FullName.Substring(4, 1) <> "C" AndAlso t.FullName <> "DAL.InitDataBase" Then
               obj = d.CreateInstance(t.FullName)
               'obj = Activator.CreateInstance(t)
               obj.save()
           End If

       Next
   End Function
   Public Shared Function initNoCode2()
       Dim d As [Assembly] = [Assembly].Load("DAL")
       Dim types As Type() = d.GetTypes()
       Dim t As Type

       'DevExpress.Xpo.Session.DefaultSession.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + HttpContext.Current.Server.MapPath("/") + "workdb\FamilyService.mdb;"
       'DevExpress.Xpo.Session.DefaultSession.AutoCreateOption = AutoCreateOption.SchemaOnly
       'Dim session As New DevExpress.Xpo.Session
       'session.ConnectionString = DevExpress.Xpo.Session.DefaultSession.ConnectionString
       'session.AutoCreateOption = AutoCreateOption.SchemaOnly

       For Each t In types
           Dim obj As New Object
           If t.FullName = "DAL.C_Occupation" Then
               obj = d.CreateInstance(t.FullName)
               obj.save()
           Else
               If t.FullName.Substring(4, 1) <> "C" AndAlso t.FullName <> "DAL.InitDataBase" Then
                   obj = d.CreateInstance(t.FullName)
                   'obj = Activator.CreateInstance(t)
                   obj.save()
               End If
           End If
       Next
   End Function

3.删除所有表的数据(前提是表之间无联系)
   Public Shared Function DelData()
       Dim d As [Assembly] = [Assembly].Load("DAL")
       Dim types As Type() = d.GetTypes()
       Dim t As Type
       Dim tbName As String
       Dim command As IDbCommand
       command = DevExpress.Xpo.Session.DefaultSession.ConnectionProvider.CreateCommand()

       For Each t In types
           Dim obj As New Object
           If t.FullName.Substring(4, 1) <> "C" AndAlso t.FullName <> "DAL.InitDataBase" Then
               tbName = t.FullName.Substring(4)
               command.CommandText = "Delete From " + tbName
               command.ExecuteNonQuery()
           End If

       Next
   End Function



下载个reflector自己看

http://www.aisto.com/roeder/dotnet/

http://community.csdn.net/Expert/topic/4318/4318117.xml?temp=9.945315E-02
http://community.csdn.net/Expert/topic/4345/4345542.xml?temp=.5111048

http://search.microsoft.com/search/results.aspx?view=zh-cn&st=a&na=81&qu=%e5%8f%8d%e5%b0%84



假设另一个工程中的所有类都编译到一个dll文件中了,在这很多的类当中,有一个类叫StringUtil,名称空间在HSMP.CommonBasic.Common下
该类中有一个方法:
public double GetSum(double x,double y)
{
return x+y;
}
编译后dll文件的存放路径是:D:\Test\HSMP.CommonBasic.dll
现在的问题是,如何通过程序调用该dll文件中的GetSum方法
大概有以下几步:
using System.Reflection;
A.
//这里要用LoadFrom,只有在本工程里添加了该dll的引用后才可以使用Load
Assembly objAss = Assembly.LoadFrom(@"D:\Test\HSMP.CommonBasic.dll");
//HSMP.CommonBasic.Common.StringUtil类的全路径
Type t=objAss.GetType("HSMP.CommonBasic.Common.StringUtil");
//动态生成类StringUtil的实例
object obj=System.Activator.CreateInstance(t);
//参数信息,GetSum需要两个int参数,如果方法没有参数,就声明一个长度为0的数组
System.Type[] paramTypes = new System.Type[2];
paramTypes[0] = System.Type.GetType("System.Int32");
paramTypes[1] = System.Type.GetType("System.Int32");
//找到对应的方法
MethodInfo p = t.GetMethod("SayHello", paramTypes)
//参数值,如果所调用的方法没有参数,不用写这些
Object[] parameters = new Object[2];
parameters[0] = 3;
parameters[1] = 4;
object objRetval = p.Invoke(obj, parameters); //如果没有参数,写null即可。


----------------------------------------------------------------

using System.Reflection;


Assembly a = Assembly.LoadFrom(@"D:\MaryKay\CommonBasic\bin\MaryKay.CommonBasic.dll");
foreach(Type t in a.GetTypes())
{
Response.Write(t.NameSpace);//类的命名空间
Response.Write(t.Name);//类的名称
}


--------------------
1、eXpress.Persistent.Object.v.1.5的新特性
映射已存在的数据库。XPBaseObject做为基类可为持久性对象提供服务。
支持MSSQL7.0(^_^,这也算一个新特性?呵呵)。
页面级收集器。PageSelector类允许对一个源容器进行页面管理。
设计期的页面管理。XPPageSelector组件允许在设计时段指定一个页面容器做为数据源,并绑定到用户界面。
容器内容过滤。XPCollection.Filter属性允许过滤出已存在的容器内容,并可获取匹配过滤标准的子容器项目。
容器内容排序和过滤。非持久性属性可用于过滤和排序XPCollection容器的内容。
排序与过滤选项。XPCollection.CaseSensitive属性可控制容器成员的大小写。
新的标准运算。AggregateOperand允许通过Aggregate.Sum,Aggregate.Count,Aggregate.Min和Aggregate.Max操作选项进行运算。
支持值对象。
值与类型转换。借助于ValueConverter和ValueConverterAttribute类可以实现数据库值与持久性属性之间的双向转换。
数据库视图的映射。持久性对象现可以映射到数据库视图。
持久性空值。空值可通过NullValueAttribute被存储在数据库中。
自定义数据库类型。利用持久性属性或字段映射,利用DbTypeAttribute可明确标识出列的类型。
跟踪容器内容的更改。可通过CollectionChanged事件跟踪容器内容的更改。
性能的提高。当对象被加载时,ExplicitLoadingAttribute要帮助优化数据库查询性能。
XPBaseObject。XPBaseObject现可支持IEditableObject。可通过此接口控制对象的改变。
XPBaseObject。XPBaseObject现拥有一个虚拟的AfterConstruction方法允许实现逻辑创建自主对象。
XPCollection。XPCollection扩展CollectionChanged事件,提供在容器操作过程中执行自定义动作。

2、XPO如何工作
面向对象的应用程序设计与开发为当前的复杂应用开发提供了一个高性能与多产的手段,提高了代码重用的机会,以及当最终用户需求发生变化时更高的灵活性。

当创建一个数据库应用时,开发人员看起来总是被迫与数据表、视图、数据字段对象打交道,而不是直接处理商业对象。这种关系数据库对象领域的差距现象类似于ADO.NET和特定领域内的商业对象的差别,对开发人员来讲,同样是一极大的挑战。

Visual Studio .NET试图通过类型安全数据集来解决这个问题:一个开发人员可以拾取一个数据表并且生成一个类型安全的数据集类,使该类看上去更类似于一个事务域中的商业对象,这种机制被用于实现持久性商业对象,尽管看来此类对象更像是面向数据的一个结构。

那么有没有一种方法可以映射你设计良好的商业对象模型到关系数据库而不必处理数据表与字段呢?也许您已经猜到这个答案了。通过XPO就要以实现这样的工作。XPO从另外一个不同的角度试图来解决这个问题——通过对商业对象世界的透视。

来看一个小例子。在一个销售管理应用程序中,一个联系人的类是如下来表示的:

public class Contact {
public string FirstName;
public string LastName;
public string PhoneNumber;
public string Email;
}

很显然,在销售管理应用系统当中所有的联系人都应该保存在数据库中,因此Contact必然是一个持久化对象。要想将其持久化,其实非常之简单,所需要做的只是将其从XPObject中进行继承:

using DevExpress.Xpo;
...
public class Contact: XPObject {
public string FirstName;
public string LastName;
public string PhoneNumber;
public string Email;
}


一般在使用持久化对象之前,都要指定一个联接字符串连接到数据库,类似下面的代码:

...
Session.DefaultSession.ConnectionString="...";
Contact contact = new Contact();
contact.FirstName = "John";
contact.LastName = "Doe";
contact.Email = "jdoe@johndoe.com";
contact.Save();
...


通过以上如此简单的代码,就在.NET环境中创建了一个Contact表,并且插入一个记录到里面。

那么如何从数据库中取用该对象呢?XPO.NET提供了提供了XPCollection来取用对象:

XPCollection contacts = new XPCollection(typeof(Contact));
foreach(Contact contact in contacts) {
Console.WriteLine(contact.Email);
}

比较幸运的是,XPCollection可以作为DataGrid的数据源用以在DataGrid当中显示Contect列表:

contactDataGrid.DataSource = contacts;


如果想更改显示对象在DataGrid中的显示项目,可以对Contact.DisplayableProperties进行设置:

contacts.DisplayableProperties = "FirstName;LastName;Email";

大多数时候,并不需要从数据库中取用全部的Contact对象,而实际情况往往是按照一定的标准查找部分对象,数据库管理系统往往提供SQL查询来完成这类任务,完全可以用来代替foreach叠代:

XPCollection jdoe = new XPCollection(typeof(Contact),
new GroupOperator(GroupOperatorType.And,
new BinaryOperator("FirstName", "John"),
new BinaryOperator("LastName", "Doe")));

以上代码即查找"John Doe"对象,类似于数据库中的SQL查询语句。

缺省情况下,容器中的对象是无序的,以下代码即取用FirstName="John"并且LastName按照升序进行排序。

XPCollection jdoe = new XPCollection(typeof(Contact),
new BinaryOperator("FirstName", "John"),
new SortProperty("LastName", SortingDirection.Ascending);

在绝大部分的商业模型中,数据表都不是独立存在的,表与表之间大都存在着这样那样的关系,比如,联系人往往属于某一间公司:

using DevExpress.Xpo;
...
public class Company : XPObject {
public string Name;
public string PhoneNumber;
public string WebSite;
}

public class Contact : XPObject {
public string FirstName;
public string LastName;
public string PhoneNumber;
public string Email;
public Company Employer;
}

在数据表存在关系的情况下,XPO.NET会知道Employer属性是另外一个商业对象的引用,因而会在数据库结构中自动地维护这种关系的存在,而勿需任何手工代码来实现。

如果一个商业对象拥有子对象,比如,一个Order订单一般情况下会有若干个订单细项,这时需要给XPO.NET一个小小的“提示”,告诉它子对象将会被存储在容器当中:

using DevExpress.Xpo;
...
public class OrderLine : XPObject {
public string Description;
public double Price;
public int Quantity;
[Association("OrderLines")]
public Order Order;
}

public class Order : XPObject {
public string OrderNo;
public string Description;

[Aggregated]
[Association("OrderLines")]
public XPCollection OrderLines {
get { return GetCollection("OrderLines"); }
}
}

对象变量允许我们在程序当中进行引用,但是在程序程序运行过程中它并非是唯一存在的,因而需要在程序运行过程当中用一个唯一指示符标识出该对象来。在每一个持久性对象当中都有一个OID属性,OID标识某个指定类的唯一标识符:

Contact contact = (Contact)Session.DefaultSession.GetObjectByKey(typeof(Contact), storedOID);

通过以上的例子可以看出XPO.NET商业模型与数据表之间的透明转换,即现在开发领域讨论的比较热烈的Object-Relational Mapping,大大提高了商业的重用性和灵活性,实现了面向对象的数据库编程。在功能与Borland公司提出的ECO(Enterprise Core Object)模型非常类似,当然XPO.NET的对于数据库的连接日前只实现了SQL和Access的MDB,没办法与ECO的强大所比拟,但是使用VS.NET环境编程的朋友们,如果没办法享受C# Builder(Delphi8.NET)所提供的ECO强大魅力的情况下,使用XPO.NET是当前比较理想的选择,将编程人员的重复复杂的O\R映像关系工作中解放出来,将更我的心思应用到商业模型的实现当中。

------------------
form:http://www.rainsts.net/article.asp?id=50

XPO 使用记录

1. 一般实体类直接继承自 XPObject,如果需要自定义主键或自增字段则可继承自XPCustomObject。

2. 继承自XPBaseObject的实体类,Delete后将被直接物理删除。而XPCustomObject & XPObject的继承类则是软删除。
 (1) 实体对象软删除
 customer.Delete();
 customer.Save();
 
 (2) 物理删除
 Session.DefaultSession.PurgeObject(customer);
 
 (3) 物理删除所有被标记软删除的记录。
 Session.DefaultSession.PurgeDeletedObjects();
 
 (4) 清除数据库中所有数据。
 Session.DefaultSession.ClearDatabase();
 
 (5) 恢复被软删除的记录。
 while(true)
 {
   o = (MyObject)Session.DefaultSession.FindObject(typeof(MyObject), new NotOperator(new NullOperator("GCRecord")), true);
   if (o == null)
   {
     break;
    }
   o.GCRecord = null;
   o.Save();
  }  
 
 (6) 批量删除

 XPCollection customers = new XPCollection(typeof(Product), new BinaryOperator("Customer", "Tom"));
 Session.DefaultSession.Delete(customers);
 Session.DefaultSession.Save(customers); // persist deletion   我的1.58版本Session.Save()没有重载这个方法????

3. 继承自XPCustomeObject的类必须使用KeyAttribute指定主键,且只能指定一个字段(??????)。
 public class Customer : XPCustomObject
 {
   [Key]
   public string Name;
  }

4. 指定字段的类型和大小。
 public class Customer : XPObject
 {
   [Size(20)]
   public string Name;
   
   [DbType("nvarchar(6)"]
   public string Postcode;
   
   [DbType("Text")]
   public string Summary;
  }

5. 字段验证。缺省情况下我们使用 public field 来公开字段,改用 public property 就可以实现字段赋值验证。
 public class Customer : XPObject
 {
   private string postcode;
   public string Postcode
   {
     get { return postcode; }
     set
     {
       // ... 验证代码省略...
       postcode = value;
      }
    }
  }
 
6. 只读字段。缺省情况下XPO只为可写的公开字段或属性创建字段,我们可以通过PersistentAttribute属性来创建只读字段。NonPersistentAttribute作用则相反,表示该字段或属性不写入数据库。
 public class Customer : XPObject
 {
   [Persistent]
   public DateTime Date
   {
     get { return DateTime.Now; }
    }

   [Persistent("Date")]
   private DateTime date;
  }

7. 一对多。下面的演示代码,每个消费者有多条收货地址。
 
 "CustomerAddress" 关系名称。
 "Aggregated" 级联操作(删除、更新)。
 "Addresses" 集合属性名。
 
 public class Customer : XPObject
 {
   public string Name;
   
   [Association("CustomerAddress", typeof(Address)), Aggregated]
   public XPCollection Addresses
   {
     get { return GetCollection("Addresses"); }
    }
  }
 
 public class Address : XPObject
 {
   [Association("CustomerAddress")]
   public Customer Customer;
  }

8. 一一对应时,不会自动创建其对应对象。

 public class Customer : XPObject
 {
   public Customer()
   {
     // Do not place any code here.
    }
 
   public Customer(Session session) : base(session)
   {
     // Do not place any code here.
    }

   public Address Address;
   
   public override void AfterConstruction()
   {
     base.AfterConstruction();
     // Initialize object properties here

     Address = new Address();
    }
   ...
  }  
 
9. 多对多。每个消费者拥有多个类型,每个类型又包含消费者。
 注意两个类中关系名相同。
 public class Customer : XPObject
 {
   public string Name;
   
   [Association("CustomerType", typeof(Type)), Aggregated]
   public XPCollection Types
   {
     get { return GetCollection("Types"); }
    }
  }
 
 public class Type : XPObject
 {
   [Association("CustomerType", typeof(Customer))]
   public XPCollection Customers
   {
     get { return GetCollection("Customers"); }
    }
  }
 
10. 延迟字段。DelayedAttribute属性让字段只有在被操作的时候才载入数据,比较适合操作大数据字段。
 public class Goods: XPObject
 {
   public string Name;
   public decimal Price;
   public string CatalogId;
   ...
   private XPDelayedProperty image1 = new XPDelayedProperty();
 
   [Delayed("image1")]
   public Byte[] Image1
   {
     get { return (Byte[])image1.Value; }
     set { image1.Value = value; }
    }
}

11. 分页。注意XPO的XPCursor的作用是分页缓存,而并非我们一般情况下说的分页。和XPCollection不同,XPCursor每次只将指定数目(PageSize)的实体对象载入内存,当我们枚举操作(IEnumerable)的对象超出当前缓存,则自动读取下一页继续操作,这种方法比XPCollection要节省内存。正因为如此,XPCursor只提供了foreach单向循环操作,而不能使用索引器的方式获取实体对象。至于我们平常所用的分页方法,可以使用XPPageSelector基于XPCollection实现。

12. 连接 SQL Server
 Session.DefaultSession.Connection = new System.Data.SqlClient.SqlConnection("server=(local);uid=sa;pwd=;database=test");
 Session.DefaultSession.AutoCreateOption = AutoCreateOption.SchemaOnly;

13. NullValueAttribute 属性只是当字段等于某个特定值时,写入数据库时将值替换为DBNull。而获取时,如果值为DBNull,则使用该指示值替代。
 public class Customer : XPObject
 {
   public string Name;
   
   [NullValue("unknown email!")]
   public string Email;
  }
 
14. IndexedAttribute 索引字段
 public class Customer : XPObject
 {
   [Indexed(Unique = true)] // 无重复索引. "[Indexed]" 有重复索引。
   public string Name;
  }
 
15. XPObject.Reload()只刷新当前对象的属性,不刷新其关联子对象的属性。

16. 监视XPO自动生成SQL。在app.config 中增加下面的配置。1.58我测试无效。?????

[XML]

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="LogFileTraceListener" type="System.Diagnostics.TextWriterTraceListener"
initializeData="trace.log" />
<remove name="Default" />
</listeners>
</trace>
<switches>
<add name="XPO" value="3" />
</switches>
</system.diagnostics>
</configuration>

17. ExplicitLoadingAttribute可以指定多层引用的递归层数,以减少数据库查询,提高性能。

 class A : XPObject
 {
   public string Name = "A";
  }

 class B : XPObject
 {
   public string Name = "B";
   [ExplicitLoading(3)]
   public A A;
  }

 class C : XPObject
 {
   public string Name = "C";
   [ExplicitLoading]
   public B B;
  }

 class D : XPObject
 {
   public string Name = "D";
   [ExplicitLoading]
   public C C;
  }

 class E : XPObject
 {
   public string Name = "E";
   public D D;
  }

  缺省情况下,我们检索到E对象时,系统会自动获取(构造)其引用的对象,当引用层数很深时,就会产生多条SQL语句。此时我们可以使用[ExplicitLoading]属性合并多个查询。在上面的例子中,D被做了属性标记,那么会自动往下递归查找有该标记的引用。因此会将 D、C、B的查询构造到同一条SQL语句中,而A依然会被单独构造SQL,我们可以将B中的属性标记加上参数3,就可以将A也加到递归中,如此D、C、B、A合并到同一条SQL语句中。注意这个Depth参数表示所引用类型距离Root的深度,A距离E有3层。

18. 多ASP.net Application中使用XPO,DevExpress推荐方案是为每个Request创建一个Session,也就是说:
Stateless + Session for each Request + Connection Pool


--------------------
ORM - XPO缓存的工作方式. 如何刷新持久对象
from:http://www.rainsts.net/article.asp?id=51
我翻译的XPO官方网站的一篇文章。英文不是很好,凑活着看吧。

How the XPO cache works. How to refresh persistent objects.
XPO缓存的工作方式. 如何刷新持久对象

ArticleID: 643; Product: eXpress Persistent Objects; Version(s): 1; Technology: .NET; Updated: 11/29/2004

Description
问题描述

It's difficult to get the latest information from the underlying database: XPCollection.Reload doesn't reload the objects' content (properties), the XPObject.Reload reloads only the object' properties but doesn't reload all the related objects because all them are get from the cache.
从数据库获取最新信息是很困难的: XPCollection.Reload 不会刷新持久对象的内容(属性), XPObject.Reload 仅仅刷新它自己的属性,不会同步刷新其关联对象,所有这些都是因为它们被存入了Cache。

Solution
解决方案

There are several things about which you should be aware.
关于这个问题,有几件事你需要明白。

XPO uses an internal object cache for each operation it performs, wherever possible. For instance, every time you want to retrieve an object collection XPO queries the database for all objects that match the specified collection's criteria. While processing the objects in the query's results, XPO checks whether a given object already exists in the object cache. If the object is found in the object cache XPO initializes its properties with the data retrieved from the query's execution; otherwise, XPO creates the object's instance, initializes it and adds it to the object cache. The object is then added to the collection. The objects are preserved in the object cache until the application makes use of them. Once the application disposes of the object, the garbage collector can take care of it as the object cache uses the WeakReference class to reference the objects. To refresh the object's state or discard changes made to the object, use its own Reload method, i.e. xpObject.Reload().
在任何情况下,XPO都使用了内置对象缓存器来缓存它的所有操作。举个例子,当你试图查询一个对象集合,XPO将从数据库获取所有匹配的对象。在处理查询结果时,XPO会检查对象是否已经加入缓存,如果已加入,XPO将使用查询获得的数据更新该缓存对象的属性。如果在缓存器中没有找到该对象,XPO将创建新的对象实例,初始化相关数据并加入到缓存器。这些缓存对象引用被加入到集合返回。这些对象将一直保存在缓存器中,供系统调用。一旦系统释放它们,垃圾回收器(GC)就可以处理这些被缓存器引用的对象。要刷新对象状态或者放弃当前的修改,请使用其自身的Reload方法,如:xpObject.Reload()。

The object cache technique is very useful and effective for single-user applications and even lets you outperform ADO.NET classes. Though this technique may have the reverse effect in a multi-user application and instead hinder data retrieval. For these applications we recommend you split your application into several logical blocks that retrieve data and use an independent XPO's Session object in each logical block. In order to get up to date information from storage or discard changes made to the objects in the session, all you have to do is to create a new session object and retrieve objects from storage using this session.
在单用户程序中,对象缓存技术是非常实用而有效的,它甚至超过了ADO.NET。当然这种技术在多用户程序中存在一些副作用,阻碍了数据更新。针对这样的程序,我们建议你将程序划分为多个逻辑块,在每个逻辑块中使用独立的XPO Session去获取和调用持久对象。为了从存储器获取更新信息,或者放弃修改,你必须创建一个新的Session对象来替代当前正在使用的Session,实现从存储器上获取数据。

All that mean two things:
所有这些表明两件事:

Firstly, the "XPBaseObject.Reload" method just reloads the object properties. It performs a new query to the database, fetches the values for the all object' properties and write these values to the appropriate properties. The associated objects will not be reloaded, so if you want to reload them you should call the "Reload" method again. Such an application design will impact performance: to reload values from the database will take a lot of time. Within our applications we use a new XPO Session: we know the identifier of the desired object and just get it from another session. It looks like a workaround and it is a workaround: we are planning to change the Session design to simplify the objects reloading and cancelling (it looks like the reloading).
首先,"XPBaseObject.Reload"方法仅仅更新其自身的属性。它向数据库执行一个新的查询,取回对象的所有属性数据,并写入这些属性。关联对象并不会被刷新,因此,如果你希望更新更新它们,你必须再次调用它们的"Reload"方法。这样的程序设计会影响性能,从数据库刷新数据会耗费大量的时间。在我们的程序内部我们使用一个新的Session来处理: 我们知道希望获取的对象标识,并使用另外一个Session去得到它。这看上去象一个工作计划,事实上它确实是一个计划:我们计划改变Session设计,使得对象能够简单地被刷新或取消(看上去象刷新)。

Secondly, the "XPCollection.Reload" method can be used to refresh only the scope of objects, and it is not applicable to reload the objects' content.
其次,"XPCollection.Reload" 方法仅刷新其搜索结果,而不是用来刷新对象内容。

 

XPO handle the following complex query

SELECT * FROM EMPLOYEE

WHERE DepartmentId IN (SELECT DepartmentId FROM Permission WHERE Username = 'someuser')

SelectQuery permissions = new SelectQuery();

permissions.Tables.Add(Permission.TableName);

permissions.Columns.Add(Permission.Columns.DepartmentId);

permissions.Where.AddCondition(Permission.Columns.Username, CriteriaOperator.Equals, "someuser");

 

SelectQuery employees = new SelectQuery();

employees.Tables.Add(Employee.TableName);

employees.Where.AddCondition(Employee.Columns.DepartmentId, CriteriaOperator.In, permissions);

return employees.GetList();

public InOperator(    string propertyName,     ICollection values );

 

XPCollection entities = new XPCollection(typeof(Entity), new InOperator("Oid", new object[] {contact, company}));

 

注意:FindObject的使用:

Staff empl = Session.DefaultSession.FindObject<Staff>(
CriteriaOperator.Parse("[Name] = 'Sandra'"));

 

注意:Session.Evaluate的计算功能

decimal sumPaid = (decimal)session.Evaluate<Order>(CriteriaOperator.Parse("Sum(OrderTotals)"), 
    new BinaryOperator("OrderDate", DateTime.Today.AddDays(-10), BinaryOperatorType.Greater));
  •  

C#

Copy Code

using DevExpress.Data.Filtering;

 

CriteriaOperator criteria = new BinaryOperator("Age", 30, BinaryOperatorType.Greater);

 
为XpCollection集合设置条件
xpCollection1.Criteria = criteria;
 
using (UnitOfWork uow = new UnitOfWork(session1.DataLayer))
{
    Person person = new Person(uow);
    person.Name = "Thomas Brown";
    person.Age = 33;
 
    // Starts an explicit transaction.
    uow.ExplicitBeginTransaction();
    try {
        uow.CommitChanges();
 
        // person has been temporarily stored to a database, thus FindObject locates this person.
        Person savedPerson = uow.FindObject<Person>(CriteriaOperator.Parse("Name = ? And Age = ?", person.Name, person.Age));
 
        savedPerson.Name = "James Smith";
        savedPerson.Age = 60;
 
        // Updates person with new data.
        uow.CommitChanges();
        // Finalizes changes and closes the explicit transaction.
        uow.ExplicitCommitTransaction();//注意ExplicitCommitTransaction将保存至数据库
    } catch {
        // Rolls back changes and closes the explicit transaction.
        uow.ExplicitRollbackTransaction();
        throw;
    }
}

 

xpDataView1.Filter = CriteriaOperator.Parse("Age < 50");
xpDataView1.Filter = new BinaryOperator("Age", 50, BinaryOperatorType.Less);
xpDataView1.FilterString = "Age < 50";

注意:XPQuery的用法

using DevExpress.Xpo;

using DevExpress.Data.Filtering;

 

//...

 

Session MainSession = new Session();

XPQuery<Customer> customersQuery = new XPQuery<Customer>(MainSession);

 

CriteriaOperator criteria = customersQuery.TransformExpression(c => c.Name == "Bob");

                     

XPCollection<Customer> customers = new XPCollection<Customer>(MainSession);

customers.Criteria = criteria;

XPView可以增加属性

XPView view = new XPView(session, typeof(OrderEntry));   
view.AddProperty("RealPrice", 
  "iif(RebatePercent == 0, ArticlePrice, ArticlePrice - (ArticlePrice * RebatePercent / 100))"); 
 
XPVIEW组合查询(AND、OR)
xpView1.GroupCriteria = GroupOperator.And(new BinaryOperator("Category", "Saloon"),
    new BinaryOperator("Price", 100000, BinaryOperatorType.Less));

 XPCollection复杂查询

计算合计数<100

XPCollection collection = new XPCollection(typeof(Person), 
    CriteriaOperator.Parse("Accounts.Sum(Amount) < 100")
);
 
查询Amount=0的记录数为1
XPCollection collection = new XPCollection(typeof(Person), 
    CriteriaOperator.Parse("Accounts[Amount = 0].Count == 1")
);
 

ContainsOperator的使用

XPCollection c = new XPCollection(typeof(User),
    new GroupOperator(GroupOperatorType.And, new CriteriaOperator[] {
        new ContainsOperator("Roles", new BinaryOperator("This", programmer)),
        new BinaryOperator("Name", "%Smith%", BinaryOperatorType.Like)})
);
 
 

 

CriteriaOperator.Parse("Accounts.Avg(Amount) = 75")

Count

Returns the number of objects in a collection.

CriteriaOperator.Parse("Accounts.Count > 1")

Exists

Determines whether a collection property marked with the AssociationAttribute contains objects.

CriteriaOperator.Parse("Accounts.Exists")

Max

Returns the maximum expression value in a collection.

CriteriaOperator.Parse("Accounts.Max(Amount) > 75")

Min

Returns the minimum expression value in a collection.

CriteriaOperator.Parse("Accounts.Min(Amount) < 10")

Sum

Returns a sum of all expression values in a collection.

CriteriaOperator.Parse("Accounts.Sum(Amount) > 150")

CriteriaOperator.Parse("(Iif (Accounts.Sum(Amount) > 150, 1, 0) = 1)")

 

XPLiteObject的AutoSaveOnEndEdit属性

AutoSaveOnEndEdit用来在该对象创建时数据库是否自动更新