Nhibernate 配置

  
转自:http://blog.163.com/kele_lipeng/blog/static/8134527820138895532811/

1. hibernate-mapping


  这个元素包括以下可选的属性。schema属性,指明了这个映射所引用的表所在的schema名称。假若指定了这个属性, 表名会加上所指定的schema的名字扩展为全限定名。假若没有指定,表名就不会使用全限定名。default-cascade 指定了未明确注明cascade属性的.Net属性和集合类.Net会采取什么样的默认级联风格。 auto-import属性默认让我们在查询语言中可以使用非全限定名的类名。assembly和 namespace指定了持久化类的应用程序集名称和其所在的名称空间名。


<hibernate-mapping                                   
     schema="schemaName"                   (1) 
     default-cascade="none|save-update"    (2)
     auto-import="true|false"              (3)
     assembly="Eg"                         (4)
    namespace="Eg"                         (5)
 />            


  各选项说明:


(1)
schema (optional): 数据库schema名称。


(2)
default-cascade (可选 - 默认为 none): 默认的级联风格。


(3)
auto-import (optional - defaults to true): 指定我们在使用查询语句的时候是否可以使用非全限定名。


(4)(5)
assembly and namespace(可选): 指定映射文件中的类的应用程序集名称和其所在的名称空间名,用来生成类的非全限定名。


  如果没有设置assembly何namespace标签,我们不得不使用类的非全限定名 (namespace.类名,assembly).


  假若你有两个持久化类,它们的非全限定名是一样的,你应该设置auto-import="false"。 假若说你把一个“import过”的名字同时对应两个类, NHibernate会抛出一个异常。


二. class


 你可以使用class元素来定义一个持久化类:


<class                                               
    name="ClassName"                             (1)    
    table="tableName"                            (2)
    discriminator-value="discriminator_value"    (3)
    mutable="true|false"                         (4)
    schema="owner"                               (5)
    proxy="ProxyInterface"                       (6)
    dynamic-update="true|false"                  (7)  
    dynamic-insert="true|false"                  (8)
    select-before-update="true|false"            (9) 
    polymorphism="implicit|explicit"             (10)
    where="arbitrary sql where condition"        (11)  
    persister="PersisterClass"                   (12)
    batch-size="N"                               (13)
    optimistic-lock="none|version|dirty|all"     (14) 
    lazy="true|false"                            (15)
    abstract="true|false"              (16)
/>


 各选项说明:


(1)
name: 持久化类(或者接口)的.NET全限定名。


(2)
table: 对应的数据库表名。


(3)
discriminator-value(辨别值) (可选 - 默认和类名一样):一个用于区分不同的子类的值,在多态行为时使用。可选值包括null和not null。


(4)
mutable (可选, 默认值为 true): 表明该类的实例可变(不可变)。


(5)
schema (可选) 覆盖在根元素中指定的schema名字。


(6)
proxy (可选)指定一个接口,在延迟装载时作为代理使用。你可以在这里使用该类自己的名字。


(7)
dynamic-update (可选,默认为false): 指定用于UPDATE 的SQL将会在运行时动态生成,并且只更新那些改变过的字段。


(8)
dynamic-insert (可选, 默认为false): 指定用于 INSERT的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。


(9)
select-before-update (可选,默认值为 false): 指定NHibernate除非确定对象的确被修改了,UPDATE操作。在特定场合(实际上,只会发生在一个临时对象关联到一个新的session中去,执行update()的时候),这说明NHibernate会在UPDATE之前执行一次额外的SQL SELECT操作,来决定是否应该进行UPDATE。


(10)
polymorphism (可选, 默认值为 implicit (隐式)): 界定是隐式还是显式的使用查询多态。


(11)
where (可选) 指定一个附加的SQL WHERE 条件,在抓取这个类的对象时会一直增加这个条件。


(12)
persister (可选): 指定一个定制的 IClassPersister。


(13)
batch-size (可选,默认是1) 指定一个用于根据标识符抓取实例时使用的"batch size"(批次抓取数量)。


(14)
optimistic-lock (乐观锁定) (可选,默认是version): 决定乐观锁定的策略。


(15)
lazy (可选): 假若设置lazy="false",就会禁用延迟加载。


(16)
abstract(可选) 用于在<union-subclass>的继承结构 (hierarchies)中标识抽象超类。


  若指明的持久化类实际上是一个接口,这也是完全可以接受的。 之后你可以用元素 <subclass>来指定该接口的实际实现类。 你可以持久化任何static(静态的)内部类。 你应该使用标准的类名格式来指定类名,比如:Eg.Foo+Bar, Eg。由于HQL解析器的限制NHibernate 1.0 无法在查询里使用内部类。


  不可变类 mutable="false"不可以被应用程序更新或者删除。 这可以让NHibernate做一些小小的性能优化。


  可选的proxy属性允许延迟加载类的持久化实例。 NHibernate开始会返回实现了这个命名接口的代理类。当代理的某个方法被实际调用的时候, 真实的持久化对象才会被装载。参见下面的“用于延迟装载的代理”。


  Implicit (隐式)的多态是指,如果查询时给出的是任何超类、该类实现的接口或者该类的 名字,都会返回这个类的实例;如果查询中给出的是子类的名字,则会返回子类的实例。 Explicit (显式)的多态是指,只有在查询时给出明确的该类名字时才会返回这个类的实例; 同时只有在这个<class>的定义中作为<subclass>或者<joined-subclass>出现的子类,才会可能返回。 在大多数情况下,默认的polymorphism="implicit"都是合适的。 显式的多态在有两个不同的类映射到同一个表的时候很有用。(允许一个“轻型”的类,只包含部分表字段)。


  persister属性可以让你定制这个类使用的持久化策略。 你可以指定你自己实现 NHibernate.Persister.EntityPersister的子类,你甚至可以完全从头开始编写一个 NHibernate.Persister.IClassPersister接口的实现, 比如是用储存过程调用、序列化到文件或者LDAP数据库来实现。 参阅NHibernate.DomainModel.CustomPersister,这是一个简单的例子 (“持久化”Hashtable)。


  请注意dynamic-updatee和dynamic-insert的设置并不会继承到子类, 所以在<subclass>或者<joined-subclass>元素中可能 需要再次设置。这些设置是否能够提高效率要视情形而定。请用你的智慧决定是否使用。


  使用select-before-update通常会降低性能。如果你重新连接一个脱管(detache)对象实例 到一个Session中时,它可以防止数据库不必要的触发update。 这就很有用了。


如果你打开了dynamic-update,你可以选择几种乐观锁定的策略:


 


version(版本检查) 检查version/timestamp字段
 


all(全部) 检查全部字段
dirty(脏检查)只检察修改过的字段
none(不检查)不使用乐观锁定
  我们非常强烈建议你在NHibernate中使用version/timestamp字段来进行乐观锁定。 对性能来说,这是最好的选择,并且这也是唯一能够处理在session外进行操作的策略(例如: 在使用ISession.Update()的时候)。注意version或者是timestamp属性不能为null,不管是否使用了unsaved-value策略,或者是实例被作为是瞬态。


  从NHibernate 1.2.0开始,版本号从1开始(以前的版本从0开始),这样允许把version的属性的unsaved-value设置为0。


5.1.4. id
 被映射的类必须定义对应数据库表主键字段。大多数类有一个属性, 为每一个实例包含唯一的标识。 元素定义了该属性到数据库表主键字段的映射。
<id                                              (1)
        name="PropertyName"                      (2)
        type="typename"                          (3)
        column="column_name"                     (4)
        unsaved-value="any|none|null|id_value"   (5)
        access="field|property|nosetter|ClassName">


        <generator class="generatorClass"/>
</id>
(1)
name (可选): 标识属性的名字。


(2)
type(可选): 标识NHibernate类型的名字。


(3)
column(可选 - 默认为属性名): 主键字段的名字。


(4)
unsaved-value (可选 - 默认为一个切合实际(sensible)的值): 一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。 这可以把这种实例和从以前的session中装载过(可能又做过修改--译者注) 但未再次持久化的实例区分开来。


(5)
access (可选 - 默认为property): NHibernate用来访问属性值的策略。


如果name属性不存在,会认为这个类没有标识属性。


unsaved-value属性在NHibernate 1.0中几乎不再需要。


还有一个另外的<composite-id>定义可以访问旧式的多主键数据。 我们强烈不建议使用这种方式。


5.1.4.1. (主键生成策略)generator


 
可选的<generator>子元素是一个.NET类的名字, 用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数, 用元素来传递。


<id name="Id" type="Int64" column="uid" unsaved-value="0">
        <generator class="NHibernate.Id.TableHiLoGenerator">
                <param name="table">uid_table</param>
                <param name="column">next_hi_value_column</param>
        </generator>
</id>
所有的生成器都实现NHibernate.Id.IIdentifierGenerator接口。 这是一个非常简单的接口; 某些应用程序可以选择提供他们自己特定的实现。当然, NHibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:


increment
用于为int类型生成 唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。


identity
对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。数据库返回的主键值 返回的标识符是int类型的。


sequence
在DB2,PostgreSQL, Oracle, SAP DB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是int类型的。


hilo
使用一个高/低位算法来高效的生成int类型的标识符。给定一个表和字段(默认分别是是hibernate_unique_key 和next_hi)作为高位值得来源。 高/低位算法生成的标识符只在一个特定的数据库中是唯一的。在用户自行提供的连接中,不要使用这种生成器。


你可以使用where参数来指定表里面用了多少列数据, You can use the "where" parameter to specify the row to use in a table. This is useful if you want to use a single tabel for your identifiers, with different rows for each table.


seqhilo
使用一个高/低位算法来高效的生成int类型的标识符,给定一个数据库序列(sequence)的名字。


uuid.hex
用一个System.Guid的ToString()方法法生成字符串类型的标识符, 字符串的长度由format参数定义。


uuid.string
用一个新的System.Guid实例的byte[]转化为字符串作为标示符。


guid
使用新的System.Guid实例作为标示符。


guid.comb
使用Jimmy Nilsson的算法(请参阅http://www.informit.com/articles/article.asp?p=25862)生成一个新的System.Guid标示符。


native
根据底层数据库的能力选择identity, sequence 或者hilo中的一个。


assigned
让应用程序在 Save()之前为对象分配一个标示符。


foreign
使用另外一个相关联的对象的标识符。通常和<one-to-one>联合起来使用。


 


5.1.4.2. 高/低位算法(Hi/Lo Algorithm)


 
hilo 和 seqhilo生成器给出了两种hi/lo算法的实现, 这是一种很令人满意的标识符生成算法。 第一种实现需要一个“特殊”的数据库表来保存下一个可用的“hi”值。 第二种实现使用一个Oracle风格的序列(在被支持的情况下)。


<id name="Id" type="Int64" column="cat_id">
        <generator class="hilo">
                <param name="table">hi_value</param>
                <param name="column">next_value</param>
                <param name="max_lo">100</param>
        </generator>
</id>
<id name="Id" type="Int64" column="cat_id">
        <generator class="seqhilo">
                <param name="sequence">hi_value</param>
                <param name="max_lo">100</param>
        </generator>
</id>
很不幸,你在为NHibernate自行提供IDbConnection时无法使用hilo。 NHibernate必须能够在一个事务里获取"hi"值。


5.1.4.3. UUID算法(UUID Algorithm )


 
<id name="Id" type="String" column="cat_id">
        <generator class="uuid.hex">
            <param name="format">format_value</param>
            <param name="seperator">seperator_value</param>
        </generator>
</id>
UUID算法是调用Guid.NewGuid().ToString(format)方法生成标示符。 format参数的使用请参阅MSDN,GUID的默认分隔符是-, 这个基本不会改动。format可以决定是都替换默认的默认分隔符。 The UUID is generated by calling Guid.NewGuid().ToString(format)。


5.1.4.4. UUID字符串算法


 
这个算法调用Guid.NewGuid().ToByteArray()方法获取byte[], 然后将byte[]转换为char[]。char[]被作为一个长度 为16的字符串返回。


5.1.4.5. GUID 算法


 
guid标示符通过调用 Guid.NewGuid()创建。当在MSSQL中使用Guids标示符时做主键,外键或者是索引是为了获取更好的性能 通常使用 guid.comb。其他支持GUIDs标示的的数据库使用guid.comb能否获得性能的提升未知。


5.1.4.6. 标识字段和序列(Identity columns and Sequences)


 
对于内部支持标识字段的数据库(DB2,MySQL,Sybase,MS SQL),你可以使用identity关键字生成。 对于内部支持序列的数据库(DB2,Oracle, PostgreSQL, Interbase, McKoi,SAP DB), 你可以使用sequence风格的关键字生成。 这两种方式对于插入一个新的对象都需要两次SQL查询。


<id name="Id" type="Int64" column="uid">
        <generator class="sequence">
                <param name="sequence">uid_sequence</param>
        </generator>
</id>
<id name="Id" type="Int64" column="uid" unsaved-value="0">
        <generator class="identity"/>
</id>
对于跨平台开发,native策略会从identity, sequence 和hilo中进行选择,选择哪一个,这取决于底层数据库的支持能力。


5.1.4.7. 程序分配的标识符(Assigned Identifiers)


 
如果你需要应用程序分配一个标示符(而非NHibernate来生成它们),你可以使用assigned生成器。 这种特殊的生成器会使用已经分配给对象的标识符属性的标识符值。用这种特性来分配商业行为的关键字要特别小心(基本上总是一种可怕的设计决定)。


因为其继承天性,使用这种生成器策略的实体不能通过ISession的SaveOrUpdate()方法保存。作为替代, 你应该明确告知NHibernate是应该被save还是update,分别调用ISession的Save()或Update()方法。


5.1.5. composite-id 联合ID
 
<composite-id
        name="PropertyName"
        class="ClassName"
        unsaved-value="any|none"
        access="field|property|nosetter|ClassName">


        <key-property name="PropertyName" type="typename" column="column_name"/>
        <key-many-to-one name="PropertyName class="ClassName" column="column_name"/>
        ......
</composite-id>
如果表使用联合主键,你可以把类的多个属性组合成为标识符属性。<composite-id> 元素接受<key-property>属性映射和 <key-many-to-one>属性映射作为子元素。


<composite-id>
        <key-property name="MedicareNumber"/>
        <key-property name="Dependent"/>
</composite-id>
你的持久化类必须重载 Equals()和GetHashCode()方法,来实现组合的标识符判断等价.也必须实现可序列化。


不幸的是,这种组合关键字的方法意味着一个持久化类是它自己的标识。除了对象自己之外, 没有什么方便的“把手”可用。你必须自己初始化持久化类的实例,在使用组合关键字load()持久化状态之前, 必须填充他的联合属性。我们会在 7.4. 组件作为联合标识符(Components as composite identifiers)第 7.4 节 “组件作为联合标识符(Components as composite identifiers)”章中说明一种更加方便的方法, 把联合标识实现为一个独立的类,下面描述的属性只对这种备用方法有效:


name (可选):一个组件类型,持有联合标识(参见下一节)。


access (可选 - 默认为property): NHibernate应该使用的访问此属性值的策略


class (可选 - 默认为通过反射(reflection)得到的属性类型) : 作为联合标识的组件类名(参见下一节)。


5.1.6. 鉴别器
 
在"一棵对象继承树对应一个表"的策略中,<discriminator>元素是必需的, 它定义了表的鉴别器字段。 鉴别器字段包含标志值,用于告知持久化层应该为某个特定的行创建哪一个子类的实例。 如下这些受到限制的类型可以使用: String, Char, Int32, Byte, Short, Boolean , YesNo, TrueFalse。


<discriminator
        column="discriminator_column" 
(1)
        type="discriminator_type"      (2)
        force="true|false"             (3)
        insert="true|false"            (4)
        formula="arbitrary SQL expressi(5)on"
/>
(1)
column (可选 - 默认为 class) 鉴别器字段的名字


(2)
type (可选 - 默认为 String) 一个NHibernate字段类型的名字。


(3)
force(强制) (可选 - 默认为 false) "强制"NHibernate指定允许的鉴别器值,即使当取得的所有实例都是根类的。


(4)
insert (可选 - 默认为true) 如果你的鉴别器字段也是映射为复合标识(composite identifier)的一部分, 则需将 这个值设为false。


(5)
formula (可选) 一个SQL表达式,在类型判断(判断是父类还是具体子类-译注)时执行。可用于基于内容的鉴别器。


鉴别器字段的实际值是根据discriminator-value 和<class> and <subclass>元素中 的discriminator-value属性得来的。


force属性仅仅在这种情况下有用的:表中包含没有被映射到持久化类的附加辨别器值。 这种情况不会经常遇到。


使用formula属性你可以定义一个SQL表达式,用来判断一个行数据的类型。


<discriminator
    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
    type="Int32"/>
5.1.7. 版本(version)(可选)
 
<version>元素是可选的,表明表中包含附带版本信息的数据。 这在你准备使用 长事务(long transactions)的时候特别有用。(见后)


<version
        column="version_column"                           
(1)
        name="PropertyName"                                (2)
        type="typename"                                    (3)
        access="field|property|nosetter|ClassName"         (4)
        unsaved-value="null|negative|undefined|value"      (5)
        generated="never|always"                           (6)
/>
(1)
column (可选 - 默认为属性名): 指定持有版本号的字段名。


(2)
name 持久化类的属性名。


(3)
type (可选 - 默认是 Int32): 版本号的类型。


(4)
access (可选 - 默认是 property): NHibernate用于访问属性值的策略。


(5)
unsaved-value(可选 - 默认是undefined): 用于标明某个实例时刚刚被实例化的(尚未保存)版本属性值, 依靠这个值就可以把这种情况 和已经在先前的session中保存或装载的脱管(detached)实例区分开来。 (undefined指明应被使用的标识属性值。)


(6)
generated(可选 - 默认是 never): 表明此版本属性值是否实际上是由数据库生成的。 请参阅 5.5  “数据库生成属性(Generated Properties)”部分的讨论。


版本号必须是以下类型:Int64, Int32, Int16, Ticks,或者 Timestamp, TimeSpan。


5.1.8. timestamp (可选)
 
可选的<timestamp>元素指明了表中包含时间戳数据。 这用来作为版本的替代。 时间戳本质上是一种对乐观锁定的一种不是特别安全的实现。当然, 有时候应用程序可能在其他方面使用时间戳。


<timestamp
        column="timestamp_column"          
(1)
        name="PropertyName"                 (2)
        access="field|property|nosetter|Clas(3)sName"
        unsaved-value="null|undefined|value"(4)
        generated="never|always"            (5)
/>
(1)
column(可选 - 默认为属性名): 持有时间戳的字段名。


(2)
name: 在持久化类中的.NE风格的属性名, 其.NE类型是 DateTime的。


(3)
access (可选 - 默认是 property): NHibernate用于访问属性值的策略。


(4)
unsaved-value (可选 - 默认是null): 用于标明某个实例时刚刚被实例化的(尚未保存)版本属性值, 依靠这个值就可以把这种情况和 已经在先前的session中保存或装载的脱管(detached)实例区分开来。 (undefined 指明使用标识属性值进行这种判断。)


(5)
generated : 指出时间戳值是否实际上是由数据库生成的.请参阅5.5  “数据库生成属性(Generated Properties)”的讨论。


注意<timestamp>等价于 <version type="timestamp">。


5.1.9. property
 
<property>元素为类定义了一个持久化类的属性。


<property
        name="propertyName"                
(1)
        column="column_name"                (2)
        type="typename"                     (3)
        update="true|false"                 (4)
        insert="true|false"                 (4)
        formula="arbitrary SQL expression"  (5)
        access="field|property|ClassName"   (6)
        optimistic-lock="true|false"        (7)
        generated="never|insert|always"     (8)
/>
(1)
name: 属性的名字。


(2)
column (可选 - 默认为属性名字): 对应的数据库字段名。


(3)
type (可选): 一个NHibernate类型的名字。


(4)
update, insert (可选 - 默认为 true) : 表明用于UPDATE 和/或 INSERT 的SQL语句中是否包含这个被映射了的字段。 这二者如果都设置为false 则表明这是一个“外源性(derived)”的属性, 它的值来源于映射到同一个(或多个) 字段的某些其他属性,或者通过一个trigger(触发器)或其他程序生成。


(5)
formula (可选): 一个SQL表达式,定义了这个计算 (computed) 属性的值。计算属性没有和它对应的数据库字段。


(6)
access (可选 - 默认值为 property): NHibernate用来访问属性值的策略。


(7)
optimistic-lock (可选 - 默认为 true): 指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。 换句话说,它决定这个属性发生脏数据时版本(version)的值是否增长。


(8)
generated (可选 - 默认为 never): 表明此属性值是否实际上是由数据库生成的。 请参阅5.5  “数据库生成属性(Generated Properties)”的讨论。


typename可以是如下几种


NHibernate基本类型名(比如:Int32, String, Char, DateTime, Timestamp, Single, Byte[], Object, ...)。


一个.Net类的名字,这个类属于一种默认基础类型 (比如: System.Int16, System.Single, System.Char, System.String, System.DateTime, System.Byte[], ...)。


一个枚举类型的名字。(比如:. eg.Color)。


一个可以序列化的.NET类的名字。


一个自定义类型的类的名字。(比如: Illflow.Type.MyCustomType)。


注意你必须为所有类型(除了NHibernate基础类型)指定完整的应用程序集权限定名 (或者是在<hibernate-mapping>里面配置了assembly和namespace属性)。


NHibernate支持.NET 2.0的可空类型,这些类型和对应的非可空类型处理方式是一致的, 例如:Nullable<Int32>可以对应type="Int32"或者是type="System.Int32"。


如果你没有指定类型,NHibernate会使用反射来得到这个名字的属性, 以此来猜测正确的NHibernate类型。NHibernate会对属性读取器(getter方法)的返回类进行解释, 按照规则2,3,4的顺序。然而,这并不足够。 在某些情况下你仍然需要type属性。 (比如,为了区别NHibernateUtil.DateTime和NHibernateUtil.Timestamp,或者为了指定一个自定义类型。)


access属性用来让你控制NHibernate如何在运行时访问属性。 在默认情况下, NHibernate会按照access-strategy.naming-strategy来格式化属性名 .naming-strategy不是必填项。


表 5.1. 访问策略


访问策略名 描述
property
默认实现:NHibernate访问类的set/get属性,这种方式没有命名策略,因为name就代表属性的名称。


field
NHibernate将会直接访问成员变量。NHibernate使用name作为成员变量的名称。 当对象属性的get和set里面有额外的操作,而你不想让NHibernate设置或者读取对象时执行额外的操作, 可以用这个策略。当你使用HQL时需要属性名而非字段时,就需要命名策略(Naming Strateg)。


nosetter
NHibernate将会在设置值时直接访问字段,获得值时访问属性。 当API使用者不能直接改变值,因而只为属性只提供了get访问器时, 你可以用这个策略。NHibernate使用name属性(attribute)作为属性(Property ), 并且需要提供字段名,所以命名策略必须(Naming Strategy)使用。


ClassName
如果NHibernate内置的访问策略(Access Strategie)不能满足你的要求。 你可以通过实现NHibernate.Property.IPropertyAccessor接口来自己的访问策略(Access Strategie)。 这个值需要用程序集名(Assembly)来限定,这样就能通过 Activator.CreateInstance(string AssemblyQualifiedName)来读取。


 


 


表 5.2. 命名策略(Naming Strategy)


命名策略 描述
camelcase
name属性被转换CamelCase格式来查找字段。<property name="Foo" ... >使用foo字段。


camelcase-underscore
name属性被转换CamelCase格式并添加下划线前缀来查找字段。<property name="Foo" ... >使用_foo字段。


lowercase
name属性被转换小写格式来查找字段。<property name="FooBar" ... > 使用 foobar字段.


lowercase-underscore
name属性被转换小写格式并添加下划线前缀来查找字段。<property name="FooBar" ... >使用_foobar字段.


pascalcase-underscore
name属性添加下划线前缀来查找字段。<property name="Foo" ... >使用_Foo字段。


pascalcase-m
name属性添加字母m前缀来查找字段。<property name="Foo" ... >使用mFoo字段。


pascalcase-m-underscore
name属性添加字母m和下划线前缀来查找字段。<property name="Foo" ... > 使用m_Foo字段。


 


5.1.10. 多对一(many-to-one)
 
通过 many-to-one元素,可以定义一种常见的与另一个持久化类的关联。这种关系模型是多对一关联。(实际上是一个对象引用。)


<many-to-one
        name="PropertyName"                               
(1)
        column="column_name"                               (2)
        class="ClassName"                                  (3)
        cascade="all|none|save-update|delete"              (4)
        fetch="join|select"                                (5)
        update="true|false"                                (6)
        insert="true|false"                                (6)
        property-ref="PropertyNameFromAssociatedClass"     (7)
        access="field|property|nosetter|ClassName"         (8)
        unique="true|false"                                (9)
        optimistic-lock="true|false"                       (10)
        not-found="ignore|exception"                       (11)
/>
(1)
name:属性名。


(2)
column数据库字段名


(3)
class(可选 - 默认是通过反射得到属性类型): 关联的类的名字。


(4)
cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。


(5)
fetch (可选 - 默认为 select): 在外连接抓取(outer-join fetching)和序列选择抓取(sequential select fetching)两者中选择其一。


(6)
(可选 - defaults to true) 指定对应的字段是否包含在用于UPDATE 和/或 INSERT 的SQL语句中。如果二者都是false,则这是一个纯粹的 “外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到 或者通过trigger(触发器)、或其他程序。


(7)
property-ref: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。 如果没有指定,会使用对方关联类的主键。


(8)
access(可选 - 默认是 property): NHibernate用来访问属性的策略。


(9)
unique (可选): 使用DDL为外键字段生成一个唯一约束。此外, 这也可以用作property-ref的目标属性。这使关联同时具有 一对一的效果。


(10)
optimistic-lock (可选 - 默认为 true): 指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。 换句话说,它决定这个属性发生脏数据时版本(version)的值是否增长。


(11)
not-found (可选 - 默认为 exception): 指定外键引用的数据不存在时如何处理: ignore会将数据不存在作为关联到一个空对象(null)处理。


cascade属性允许下列值:: all, save-update, delete, none. 设置除了none以外的其它值会传播特定的操作到关联的(子)对象中。参见后面的“Lifecycle Objects(自动管理生命周期的对象)”。


fetch参数允许下列两个不同值:


join外连接抓取


select使用隔离查询抓取


一个典型的简单many-to-one 定义例子:


<many-to-one name="product" class="Product" column="PRODUCT_ID"/>
property-ref属性只应该用来对付老旧的数据库系统, 可能有外键指向对方关联表的是个非主键字段(但是应该是一个惟一关键字)的情况下。 这是一种十分丑陋的关系模型。比如说,假设Product类有一个惟一的序列号, 它并不是主键。(unique属性控制NHibernate通过SchemaExport工具生成DDL的过程。)


<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>
那么关于OrderItem 的映射可能是:


<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>
当然,我们决不鼓励这种用法。


5.1.11. 一对一
 
持久化对象之间一对一的关联关系是通过 one-to-one元素定义的。


<one-to-one
        name="PropertyName"                               
(1)
        class="ClassName"                                  (2)
        cascade="all|none|save-update|delete"              (3)
        constrained="true|false"                           (4)
        fetch="join|select"                                (5)
        property-ref="PropertyNameFromAssociatedClass"     (6)
        access="field|property|nosetter|ClassName"         (7)
/>
(1)
name: 属性的名字。


(2)
class (可选 - 默认是通过反射得到的属性类型):被关联的类的名字。


(3)
cascade(级联) (可选) 表明操作是否从父对象级联到被关联的对象。


(4)
constrained(约束) (可选) 表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。 这个选项影响Save()和Delete()在级联执行时的先后顺序以及 决定该关联能否被委托(也在schema export tool中被使用).


(5)
fetch (可选 - 默认设置为select): 在外连接抓取或者序列选择抓取选择其一.


(6)
property-ref: (可选) 指定关联类的属性名,这个属性将会和本类的主键相对应。如果没有指定,会使用对方关联类的主键。


(7)
access (可选 - 默认是 property): NHibernate用来访问属性的策略。


有两种不同的一对一关联:


主键关联


惟一外键关联


主键关联不需要额外的表字段;如果两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!


比如说,对下面的Employee和Person进行主键一对一关联:


<one-to-one name="Person" class="Person"/>
<one-to-one name="Employee" class="Employee" constrained="true"/>
现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个被成为foreign的特殊的现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个被成为foreign的特殊的hibernate标识符生成策略:标识符生成策略: foreign:


<class name="Person" table="PERSON">
    <id name="Id" column="PERSON_ID">
        <generator class="foreign">
            <param name="property">Employee</param>
        </generator>
    </id>
    ...
    <one-to-one name="Employee"
        class="Employee"
        constrained="true"/>
</class>
一个刚刚保存的Person实例被赋予和该Person的employee属性所指向的Employee实例同样的关键字值。


另一种方式是一个外键和一个惟一关键字对应,上面的Employee和Person的例子,如果使用这种关联方式,可以表达成:


<many-to-one name="Person" class="Person" column="PERSON_ID" unique="true"/>
如果在Person的映射加入下面几句,这种关联就是双向的:


<one-to-one name="Employee" class="Employee" property-ref="Person"/>
5.1.12. 组件(component), 动态组件(dynamic-component)
 
<component>元素把子对象的一些元素与父类对应的表的一些字段映射起来。 然后组件可以定义它们自己的属性、组件或者集合。参见后面的“Components”一章。


<component 
        name="PropertyName"                               
(1)
        class="ClassName"                                  (2)
        insert="true|false"                                (3)
        upate="true|false"                                 (4)
        access="field|property|nosetter|ClassName"         (5)
        optimistic-lock="true|false"                       (6)
>
        
        <property ...../>
        <many-to-one .... />
        ........
</component>
(1)
name: 属性名


(2)
class (可选 - 默认为通过反射得到的属性类型):组件(子)类的名字。


(3)
insert: 被映射的字段是否出现在SQL的INSERT语句中?


(4)
update: 被映射的字段是否出现在SQL的UPDATE语句中?


(5)
access可选 - 默认是 property): NHibernate用来访问属性的策略。


(6)
optimistic-lock (可选 - 默认是 true):表明更新此组件是否需要获取乐观锁。换句话说,当这个属性变脏时,是否增加版本号(Version


其<property>子标签为子类的一些属性与表字段之间建立映射。


<component>元素允许加入一个 <parent>子元素,在组件类内部就可以有一个指向其容器的实体的反向引用。


<dynamic-component>元素允许把一个 IDictionaryp映射为组件,其属性名对应键值。 参见第 8.5 节 “动态组件 (Dynamic components)”.


5.1.13. 子类(subclass)
 
最后,多态持久化需要为父类的每个子类都进行定义。 对于“每一棵类继承树对应一个表”的策略来说,就需要使用<subclass>定义。


<subclass
        name="ClassName"                             
(1)
        discriminator-value="discriminator_value"     (2)
        proxy="ProxyInterface"                        (3)
        lazy="true|false"                             (4)
        dynamic-update="true|false"
        dynamic-insert="true|false">


        <property .... />
        .....
</subclass>
(1)
name: 子类的全限定名。


(2)
discriminator-value (辨别标志) (可选 - 默认为类名):一个用于区分每个独立的子类的值。


(3)
proxy(代理) (可选): 指定一个类或者接口,在延迟装载时作为代理使用。


(4)
lazy(可选, 默认是true): 设置为 lazy="false" 禁止使用延迟抓取。


每个子类都应该定义它自己的持久化属性和子类。 <version> 和<id>属性可以从根父类继承下来。 在一棵继承树上的每个子类都必须定义一个唯一的discriminator-value。如果没有指定,就会使用.NET类的全限定名。


更多关于继承映射的信息, 参考 8. 继承映射章节.


5.1.14. 连接的子类(joined-subclass)
 
此外,每个子类可能被映射到他自己的表中(每个子类一个表的策略)。被继承的状态通过和超类的表关联得到。我们使用<joined-subclass>元素。


<joined-subclass
        name="ClassName"                   
(1)
        proxy="ProxyInterface"              (2)
        lazy="true|false"                   (3)
        dynamic-update="true|false"
        dynamic-insert="true|false">


        <key .... >


        <property .... />
        .....
</joined-subclass>
(1)
name: 子类的全限定名。


(2)
proxy (可选): 指定一个类或者接口,在延迟装载时作为代理使用。


(3)
lazy(可选, 默认是 true): 设置为 lazy="false" 禁止使用延迟装载。 等价于设置proxy为自身类。


这种映射策略不需要指定辨别标志(discriminator)字段。但是,每一个子类都必须使用 <key>元素指定一个表字段来持有对象的标识符。本章开始的映射可以被用如下方式重写:


<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Eg"
    namespace="Eg">


        <class name="Cat" table="CATS">
                <id name="Id" column="uid" type="Int64">
                        <generator class="hilo"/>
                </id>
                <property name="BirthDate" type="Date"/>
                <property name="Color" not-null="true"/>
                <property name="Sex" not-null="true"/>
                <property name="Weight"/>
                <many-to-one name="Mate"/>
                <set name="Kittens">
                        <key column="MOTHER"/>
                        <one-to-many class="Cat"/>
                </set>
                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
                    <key column="CAT"/>
                        <property name="Name" type="String"/>
                </joined-subclass>
        </class>


        <class name="Dog">
                <!-- mapping for Dog could go here -->
        </class>


</hibernate-mapping>
更多关于继承映射的信息,参考 9. 继承继承。


5.1.15. 联合子类(union-subclass)
 
第三种选择是仅仅映射类继承树中具体类部分到表中(每个具体类一张表的策略)。 其中,每张表定义了类的所有持久化状态,包括继承的状态。 在 NHibernate 中,并不需要完全显式地映射这样的继承树。 你可以简单地使用单独的<class>定义映射每个类。 然而,如果你想使用多态关联(例如,一个对类继承树中超类的关联),你需要使用<union-subclass>映射。


<union-subclass
        name="ClassName"                   
(1)
        table="tablename"                   (2)
        proxy="ProxyInterface"              (3)
        lazy="true|false"                   (4)
        dynamic-update="true|false"
        dynamic-insert="true|false"
        schema="schema"
        catalog="catalog"
        extends="SuperclassName"
        abstract="true|false"
        persister="ClassName"
        subselect="SQL expression"
        entity-name="EntityName"
        node="element-name">


        <property .... />
        .....
</union-subclass>
(1)
name: 子类的全限定名。


(2)
table: 子类的表名


(3)
proxy (可选): 指定一个类或者接口,在延迟装载时作为代理使用。


(4)
lazy (可选, 默认是 true): 设置为 lazy="false" 禁止使用延迟装载。


这种映射策略不需要指定辨别标志(discriminator)字段。


更多关于继承映射的信息,参考 9. 继承继承。


5.1.16. 连接(join)
 
使用 <join> 元素,可以将一个类的属性映射到多张表中。 当表之间存在一对一关系的时候使用。


<join
        table="tablename"                       
(1)
        schema="owner"                           (2)
        fetch="join|select"                      (3)
        inverse="true|false"                     (4)
        optional="true|false">                   (5)


        <key ... />


        <property ... />
        ...
</join>
(1)
table: 被连接表的名称。


(2)
schema (可选):覆盖由根<hibernate-mapping>元素指定的模式名称。


(3)
fetch (可选 - 默认是 join): 如果设置为默认值join, NHibernate 将使用一个内连接来得到这个类或其超类定义的join ,而使用一个外连接来得到其子类定义的join。如果设置为select, 则 NHibernate 将为子类定义的 join使用顺序选择。 这仅在一行数据表示一个子类的对象的时候才会发生。对这个类和其超类定义的join,依然会使用内连接得到。


(4)
inverse(可选 - 默认是 false): 如果打开,NHibernate 不会插入或者更新此连接定义的属性。


(5)
optional (可选 - 默认是 false): 如果打开,NHibernate 只会在此连接定义的属性非空时插入一行数据,并且总是使用一个外连接来得到这些属性。


例如,一个人(person)的地址(address)信息可以被映射到单独的表中(并保留所有属性的值类型语义):


<class name="Person"
    table="PERSON">


    <id name="id" column="PERSON_ID">...</id>


    <join table="ADDRESS">
        <key column="ADDRESS_ID"/>
        <property name="address"/>
        <property name="zip"/>
        <property name="country"/>
    </join>
    ...
此特性常常对遗留数据模型有用,我们推荐表个数比类个数少,以及细粒度的领域模型。然而,在单独的继承树上切换继承映射策略是有用的,后面会解释这点。


5.1.17. map, set, list, bag
 
集合类型稍后讨论。


5.1.18. 引用
 
假设你的应用程序有两个同样名字的持久化类,但是你不想在Hibernate查询中使用他们的全限定名。 除了依赖auto-import="true"以外,类也可以被显式地“import(引用)”。你甚至可以引用没有明确被映射的类和接口。


<import class="System.Object" rename="Universe"/>
<import
        class="ClassName"              (1)
        rename="ShortName"             (2)
/>
(1)
class: 任何.NET类的全限定名。包括应用程序集名


(2)
rename(可选 - 默认为类的全限定名): 在查询语句中可以使用的名字。  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NHIBERNATE - 符合.Net习惯的关系数据库持久化 NHibernate参考文档 2.0.0 -------------------------------------------------------------------------------- 目录 前言 1. 第一个NHibernate应用程序 1.1. 开始NHibernate之旅 1.2. 第一个持久化类 1.3. 映射cat 1.4. 与Cat同乐 1.5. 总结 2. 体系结构(Architecture) 2.1. 概况(Overview) 2.2. 实例状态 2.3. 上下文相关的(Contextual)Session 3. 配置 3.1. 可编程的配置方式 3.2. 获得ISessionFactory 3.3. 用户自行提供ADO.NET连接 3.4. NHibernate提供ADO.NET连接 3.5. 可选的配置属性 3.5.1. SQL方言 3.5.2 外连接抓取(Outer Join Fetching) 3.5.3. 查询缓存 3.5.4. 查询语言中的替换 3.6. 日志 3.7. 实现NamingStrategy 3.8. XML配置文件 4. 持久化类(Persistent Classes) 4.1. 一个简单的POCO例子 4.1.1. 为持久化成员变量声明读写属性 4.1.2. 实现一个默认的构造器(constructor) 4.1.3. 提供一个标识属性(identifier property)(可选) 4.1.4. 使用非不可继承的(non-sealed)类以及虚方法(virtual methods) (可选) 4.2. 实现继承(Inheritance) 4.3. 实现 Equals() 和 GetHashCode() 方法 4.4. 持久化生命周期(Lifecycle)中的回调(Callbacks) 4.5. 合法性验证(IValidatable)回调 5. 对象/关系数据库映射基础(Basic O/R Mapping) 5.1. 映射定义(Mapping declaration) 5.1.1. XML名称空间 5.1.2. hibernate-mapping 5.1.3. class 5.1.4. id 5.1.4.1. (主键生成策略)generator 5.1.4.2. 高/低位算法(Hi/Lo Algorithm) 5.1.4.3. 唯一标识16进制算法(UUID Algorithm ) 5.1.4.4. 唯一标识字符串算法 5.1.4.5. 唯一标识GUID算法 5.1.4.6. 标识字段和序列(Identity columns and Sequences) 5.1.4.7. 程序分配的标识符(Assigned Identifiers) 5.1.5. (联合主键)composite-id 5.1.6. 鉴别器(discriminator) 5.1.7. 版本(version)(可选) 5.1.8. 时间戳 (可选) 5.1.9. 属性 5.1.10. 多对一 5.1.11. 一对一 5.1.12. 组件(component), 动态组件(dynamic-component) 5.1.13. 子类 5.1.14. 连接的子类(joined-subclass) 5.1.15. 联合子类(union-subclass) 5.1.16. 连接 5.1.17. map, set, list, bag 5.1.18. 引用(import) 5.2. NHibernate 的类型 5.2.1. 实体(Entities)和值(values) 5.2.2. 基本值类型 5.2.3. 自定义值类型 5.2.4. Any类型映射 5.3. SQL中引号包围的标识符 5.4. 模块化映射文件 5.5. 数据库生成属性(Generated Properties) 5.6. 数据库辅助对象 6. 集合类(Collections)映射 6.1. 持久化集合类 6.2. 集合外键(Collection foreign keys) 6.3. 值集合于多对多关联(Collections of values and many-to-many associations) 6.4. 一对多关联 6.5. 延迟加载 6.6. 有序集合(Sorted collections) 6.7. 使用<idbag> 6.8. 双向关联(Bidirectional associations) 6.9. 三重关联(Ternary associations) 6.10. 异质关联(Heterogeneous Associations) 6.11. 集合例子(Collection example) 7. 组件(Component)映射 7.1. 依赖对象(Dependent objects) 7.2. 在集合中出现的依赖对象 (Collections of dependent objects) 7.3. 组件作为IDictionary的索引(Components as IDictionary indices ) 7.4. 组件作为联合标识符(Components as composite identifiers) 7.5. 动态组件 8. 继承映射(Inheritance Mappings) 8.1. 三种策略 8.1.1. 每个类分层结构一张表(Table per class hierarchy) 8.1.2. 每个子类一张表(Table per subclass) 8.1.3. 每个子类一张表(Table per subclass),使用辨别标志(Discriminator) 8.1.4. 混合使用“每个类分层结构一张表”和“每个子类一张表” 8.1.5. 每个具体类一张表(Table per concrete class) 8.1.6. 每个具体类一张表使用隐式多态 8.1.7. 隐式多态和其他继承映射混合使用 8.2. 限制 9. 持久化数据管理 9.1. 创建持久化对象 9.2. 加载载对象 9.3. 查询 9.3.1. 标量(Scalar)查询 9.3.2. IQuery接口 9.3.3. 过滤集合 9.3.4. 条件查询(Criteria queries) 9.3.5. 使用原生SQL的查询 9.4. 修改持久化对象 9.4.1. 使用同一个ISession持久化对象 9.4.2. 修改脱管(Detached)对象 9.4.3. 重新附脱管(Detached)对像 9.5. 删除持久化对象 9.6. 刷出 9.7. 结束ISession 9.7.1. 清除ISession 9.7.2. 提交数据库事务 9.7.3. 关闭ISession 9.8. 异常处理 9.9. 生命周期与对象图 9.10. 拦截器 9.11. 元数据API 10. 事务和并发 10.1. 配置,会话与工厂 10.2. 线程与连接 10.3. 关注对象标识(Considering object identity) 10.4. 乐观并发控制(Optimistic concurrency control) 10.4.1. 长会话自动版本化 10.4.2. 多事务自动版本化 10.4.3. 定制自动版本化行为 10.4.4. 应用程序级别的版本检查(Application version checking) 10.5. 会话断开连接 10.6. 悲观锁定(Pessimistic Locking) 10.7. 连接释放模式(Connection Release Modes) 11. 拦截器与事件 11.1. 拦截器 11.2. 事件系统 12. HQL: NHibernate查询语言 12.1. 大小写敏感性问题 12.2. from子句 12.3. 关联(Association)与连接(Join) 12.4. select子句 12.5. 聚集函数 12.6. 多态查询 12.7. where子句 12.8. 表达式 12.9. order by子句 12.10. group by子句 12.11. 子查询 12.12. HQL示例 12.13. 小技巧 & 小窍门 13. 条件查询(Criteria Queries) 13.1. 创建一个ICriteria实例 13.2. 限制结果集内容 13.3. 结果集排序 13.4. 关联 13.5. 动态关联抓取 13.6. 查询示例 13.7. 投影(Projections)、聚合(aggregation)和分组(grouping) 13.8. 离线(detached)查询和子查询 14. 原生SQL查询 14.1. 使用ISQLQuery 14.1.1. 标量查询(Scalar queries) 14.1.2. 实体查询(Entity queries) 14.1.3. 处理关联和集合类(Handling associations and collections) 14.1.4. 返回多个实体(Returning multiple entities) 14.1.4.1. 别名和属性引用(Alias and property references) 14.1.5. 返回非受管实体(Returning non-managed entities) 14.1.6. 处理继承(Handling inheritance) 14.1.7. 参数(Parameters) 14.2. 命名SQL查询 14.2.1. 使用return-property来明确地指定字段/别名 14.2.2. 使用存储过程来查询 14.2.2.1. 使用存储过程的规则和限制 14.3. 定制SQL用来create,update和delete 14.4. 定制装载SQL 15. 过滤数据 15.1. NHibernate 过滤器(filters) 16. 提升性能 16.1. 抓取策略(Fetching strategies) 16.1.1. 操作延迟加载的关联 16.1.2. 调整抓取策略(Tuning fetch strategies) 16.1.3. 单端关联代理(Single-ended association proxies) 16.1.4. 初始化集合和代理(Initializing collections and proxies) 16.1.5. 使用批量抓取(Using batch fetching) 16.1.6. 使用子查询抓取(Using subselect fetching) 16.2. 二级缓存(The Second Level Cache) 16.2.1. 缓存映射(Cache mappings) 16.2.2. 策略:只读缓存(Strategy: read only) 16.2.3. 策略:读/写缓存(Strategy: read/write) 16.2.4. 策略:非严格读/写缓存(Strategy: nonstrict read/write) 16.2.5. 并发策略兼容性 16.3. 管理缓存(Managing the caches) 16.4. 查询缓存(The Query Cache) 16.5. 理解集合性能(Understanding Collection performance) 16.5.1. 分类(Taxonomy) 16.5.2. Lists, maps 和sets用于更新效率最高 16.5.3. Bag和list是反向集合类中效率最高的 16.5.4. 一次性删除(One shot delete) 16.6. 批量更新(Batch updates) 16.7. Multi Query 16.8. 多重条件查询 17. 工具箱指南 17.1. 数据库结构生成(schema generation) 17.1.1. 对schema定制化(Customizing the schema) 17.1.2. 运行该工具 17.1.3. 配置属性(Properties) 17.1.4. 使用NAnt 17.2. 代码生成 17.2.1. 配置文件(可选) 17.2.2. 元数据属性 17.2.3. 基本的finder生成器(Basic finder generator) 17.2.4. 基于Velocity的渲染器/生成器(Velocity based renderer/generator) 17.3. 映射文件生成器(Mapping File Generation) 17.3.1. 运行工具 18. 示例:父子关系(Parent Child Relationships) 18.1. 关于collections需要注意的一点 18.2. 双向的一对多关系(Bidirectional one-to-many) 18.3. 级联生命周期(Cascading lifecycle) 18.4. 使用级联更新 18.5. 结论 19. 示例:Weblog 应用程序 19.1. 持久化类 19.2. NHibernate 映射 19.3. NHibernate 代码 20. 示例:复杂映射实例 20.1. Employer(雇主)/Employee(雇员) 20.2. Author(作家)/Work(作品) 20.3. Customer(客户)/Order(订单)/Product(产品) 21. 最佳实践 I. NHibernateContrib 参考文档 前言 22.2. Prevalence Cache 配置 22.1. 如何使用缓存? 22.2. Prevalence Cache 配置 22.3. SysCache 配置 22.4. SysCache2 配置 22.4.1. 表依赖缓存 22.4.2. SQL依赖缓存 22.4.3. 聚集依赖缓存 22.4.4. 附加设置 22.4.5. 补丁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值