导航

Chapter Schema

Posted on 2015-10-08 23:31  木儿壳子  阅读(195)  评论(0编辑  收藏  举报

Chapter Schema

 

SchemaXF的核心,每一个读写方法都有一个相关联的Schema。方法首先解析Schema,然后再根据Schema的配置的执行。

 

Schema是什么呢?Schema是一个XElement,它的构成如下:

 

DatabaseSchema = Database Structure + NameMap + DatabaseConfig

 

PrimarySchema(一个) = DatabaseSchema + PrimaryConfig

 

NamedSchema(多个)= PrimarySchema + NamedConfig(多个)

 

Schema = PrimarySchema NamedSchema + modifying(可选)

 

以上+号,代表Modify+号右边的用来修改左边的,除了Database StructureNameMap,其余均为XElement

 

首先XF从数据库获得数据库结构(Database Structure),然后根据 NameMap,指定TableNameColumnNameSetName ElementNameFieldName的映射。最后用DatabaseConfig修饰(Modify),得到DatabaseSchema。举例如下:

 

注:修饰(Modify)类似文件夹Copy,目标文件夹中存在的文件覆盖,不存在的添加。

 

如在数据库中有

TableUsers

PrimaryKeyId

ColumnName

DataType

AllowDBNull

Id

int

N

UserName

nvarchar(50)

N

Password

nvarchar(50)

N

Description

nvarchar(254)

Y

 

对应的XML,有一种形式如下(丢掉了nvarchar的长度)

  <Users PrimaryKey="Id">

    <Id AllowDBNull="False" SqlDbType="int"/>

    <UserName AllowDBNull="False" SqlDbType="nvarchar"/>

<Password AllowDBNull="False" SqlDbType="nvarchar"/>

    <Description AllowDBNull="True" SqlDbType="nvarchar"/>

  </Users>

 

给上述XML变个形,加点料,看上去像个User

  <User Table="Users" Set="Users" PrimaryKey="Id">

    <Id Column="Id" DataType="System.Int32" AllowDBNull="False" SqlDbType="int"/>

    <UserName Column="UserName" DataType="System.String" AllowDBNull="False" SqlDbType="nvarchar"/>

<Password Column="Password" DataType="System.String" AllowDBNull="False" SqlDbType="nvarchar"/>

    <Description Column="Description" DataType="System.String" AllowDBNull="True" SqlDbType="nvarchar"/>

  </User>

 

XF把整个<User>称之为ElementSchemaUser称为ElementName<Id><UserName><Password><Description>称之为FieldSchema,同样IdUserNamePasswordDescription称为FieldName<User>还有一个重要的属性Set,这里Set意为集合,而不是设置,同理把Users称之为SetName(集合名)。

 

ColumnNameFieldName一样的时候,可以省略Column属性,因此,User类的XML,可以简化为:

 

  <User Table="Users" Set="Users" PrimaryKey="Id">

    <Id DataType="System.Int32" AllowDBNull="False" SqlDbType="int"/>

    <UserName DataType="System.String" AllowDBNull="False" SqlDbType="nvarchar"/>

<Password DataType="System.String" AllowDBNull="False" SqlDbType="nvarchar"/>

    <Description DataType="System.String" AllowDBNull="True" SqlDbType="nvarchar"/>

  </User>

 

XF内置了PrefixSuffixNameMapSingularPluralNameMap二个类,用来把数据库中的每个表(和视图)生成类XML。(还有Foreign key生成Relationship,后述)。这二个类都继承自NameMap类。

 

上述例子中,用到的就是SingularPluralNameMap。其构造函数为:

public SingularPluralNameMap(XElement nameMapConfig)

 

当以复数形式命名数据库表时,请使用改类。参数nameMapConfig用来修饰(按单复数规律)生成后的XML

譬如某些名词单复数一样或者你喜欢取一个自己喜欢的名称。如有以下nameMapConfig

 

  <UserElement Table="Users" Set="UserSet">

    <Descr Column="Description" />

  </UserElement>

 

则最终UserXML如下:

 

  <UserElement Table="Users" Set="UserSet" PrimaryKey="Id">

    <Id DataType="System.Int32" AllowDBNull="False" SqlDbType="int"/>

    <UserName DataType="System.String" AllowDBNull="False" SqlDbType="nvarchar"/>

<Password DataType="System.String" AllowDBNull="False" SqlDbType="nvarchar"/>

    <Descr Column="Description" DataType="System.String" AllowDBNull="True" SqlDbType="nvarchar"/>

  </UserElement>

 

PrefixSuffixNameMap 假定表名是单数,用来Prefix + TableName + Suffix来命名SetName,参数nameMapConfig见上。

它有如下二个构造函数:

 

public PrefixSuffixNameMap(XElement nameMapConfig, string prefix, string suffix)

 

// 相当 public PrefixSuffixNameMap(XElement nameMapConfig, string prefix="SetOf", string suffix=string.Empty)

public PrefixSuffixNameMap(XElement nameMapConfig)

 

使用该类,则最终UserXML如下:

 

  <Users Table="Users" Set="SetOfUsers" PrimaryKey="Id">

    <Id DataType="System.Int32" AllowDBNull="False" SqlDbType="int"/>

    <UserName DataType="System.String" AllowDBNull="False" SqlDbType="nvarchar"/>

<Password DataType="System.String" AllowDBNull="False" SqlDbType="nvarchar"/>

    <Description DataType="System.String" AllowDBNull="True" SqlDbType="nvarchar"/>

  </Users>

 

数据库中不单有表(和视图),还有“关系”,二个表之间的关系,依赖Foreign key。同样,XF会把Foreign keyXML描述,称之为Relationship

Relationship用到的名称均为ElementNameFieldName,而不是TableNameColumnName。下图所示表间Foreign key

 

 

 

会生成:

 

<Relationship From="Employee" To="Job" Type="ManyToOne" Content="Employee(JobId),Job(Id)"/>

<Relationship From="User" To="Employee" Type="ManyToOne" Content="User(EmployeeId),Employee(Id)"/>

<Relationship From="UserRole" To="Role" Type="ManyToOne" Content="UserRole(RoleId),Role(Id)"/>

<Relationship From="UserRole" To="User" Type="ManyToOne" Content="UserRole(UserId),User(Id)"/>

 

注:如果,你不喜欢在数据库中设置Foreign key,上面的那些Relationship,就需要通过DatabaseConfigPrimaryConfig修饰(添加)到DatabaseSchemaPrimarySchema

 

注:在生成PrimarySchema时,会自动(推导出)加上下列多对多的Relationship

<Relationship From="Role" To="User" Type="ManyToMany" Content="Role(Id),UserRole(RoleId);UserRole(UserId),User(Id)"/>

 

注:在DatabaseConfigPrimaryConfig(在PrimaryConfig更合适),还可以添加如下<ReferencePath>

<ReferencePath Name=” User- Job” From="User" To="Job" Content="User(EmployeeId),Employee(Id);Employee(JobId),Job(Id)">

XF把二个及以上ManyToOneOneToOneToOne方向串联起来称之为ReferencePath,一般地ReferencePath有一个Name属性,以方便引用(如ReferencePath.Name=” User- Job”)。ReferencePath提供二个表之间间接的关联。

 

至此DatabaseSchema初稿已经生成,如果还有要补充的内容,可通过DatabaseConfig(也可以通过PrimaryConfig)修饰。

DatabaseConfig典型应用就是为表(Table)中的一列(Column,通常为主键)指定序列(Sequence)。

如在DatabaseConfig中有如下片段:

 

  ……

<Employee>

    <Id>

      <Sequence>

        <SequenceName>Sequence-Employees</SequenceName>

      </Sequence>

    </Id>

         ……

  </Employee>

……

  <User>

    <Id>

      <Sequence>

        <SequenceName>Sequence-Users</SequenceName>

      </Sequence>

    </Id>

         ……

  </User>

  ……

 

修饰后DatabaseSchema 相应片段为

 

  ……

  <Employee Table="Employees" PrimaryKey="Id" Set="Employees" TableType="Table">

    <Id DataType="System.Int32" AllowDBNull="False" Unique="True" ReadOnly="False" SqlDbType="int">

      <Sequence>

        <SequenceName>Sequence-Employees</SequenceName>

      </Sequence>

    </Id>

……

  </Employee>

  ……

  <User Table="Users" PrimaryKey="Id" Set="Users" TableType="Table">

    <Id DataType="System.Int32" AllowDBNull="False" Unique="True" ReadOnly="False" SqlDbType="int">

      <Sequence>

        <SequenceName>Sequence-Users</SequenceName>

      </Sequence>

    </Id>

         ……

  </User>

  ……

 

XF把作为子节点插入的Element称之为Attribute。实际也对应一个继承自Attribute的类。

<Sequence>为例,对应:

    public class SequenceAttribute : Attribute

    {

        public string SequenceName { get; private set; }

 

        public SequenceAttribute(string sequenceName)

        {

            SequenceName = sequenceName;

        }

    }

 

注意与XAttribute的区别,如下XML片段,TablePrimaryKeySetTableType都是XAttribute(属于User的),同样DataTypeAllowDBNullUniqueReadOnlySqlDbType也是(属于Id的)

<User Table="Users" PrimaryKey="Id" Set="Users" TableType="Table">

    <Id DataType="System.Int32" AllowDBNull="False" Unique="True" ReadOnly="False" SqlDbType="int">

这些XAttribute,属于不可配置的数据库属性。方法解析Schema时,只会解析Attribute,而不会理会XAttribute

 

XF另外还定义了一个PrimeAttribute类(标记类,无参构造函数,无属性),用于<Relationship><ReferencePath>标注首选项。

 

除了XF自己定义的二个Attribute类,还支持下列.NET Framework Attribute类:

(也支持System.ComponentModel.DataAnnotations.ValidationAttribute的子类,详见Chapter Data Validation,在此处不列出)

System.ComponentModel.DataAnnotations.KeyAttribute

System.ComponentModel.DataAnnotations.TimestampAttribute

System.ComponentModel.DataAnnotations.ConcurrencyCheckAttribute

System.ComponentModel.DefaultValueAttribute

System.ComponentModel.DisplayNameAttribute

System.ComponentModel.DataAnnotations.DisplayAttribute

 

一个真实的DatabaseSchema片段:

 

  <User Table="Users" PrimaryKey="Id" Set="Users" TableType="Table">

    <Id DataType="System.Int32" AllowDBNull="False" Unique="True" ReadOnly="False" SqlDbType="int">

      <Key/>

      <Sequence>

        <SequenceName>Sequence-Users</SequenceName>

      </Sequence>

    </Id>

    <EmployeeId DataType="System.Int32" AllowDBNull="False" Unique="False" ReadOnly="False" SqlDbType="int">

      <Required/>

    </EmployeeId>

    <UserName DataType="System.String" AllowDBNull="False" Unique="True" ReadOnly="False" SqlDbType="nvarchar">

      <Required/>

    </UserName>

    <Password DataType="System.String" AllowDBNull="False" Unique="False" ReadOnly="False" SqlDbType="nvarchar">

      <Required/>

      <DefaultValue>

        <Value>a1b2c3</Value>

      </DefaultValue>

    </Password>

    <Description DataType="System.String" AllowDBNull="True" Unique="False" ReadOnly="False" SqlDbType="nvarchar"/>

  </User>

 

至此DatabaseSchema已完全生成,再经由PrimaryConfig修饰(Modify),就得到PrimarySchema

如上所述,DatabaseConfig的内容,全都可以放在PrimaryConfigDatabaseConfig甚至可以没有。DatabaseConfig的存在,是为了层次更清晰。除了这些PrimaryConfig还可以有哪些内容呢?PrimaryConfig的主要作用就是横向扩展Field。如有以下PrimaryConfig片段:

 

  <User>

    <Employee.Name Element="Employee" Field="Name" Relationship.Content="User(EmployeeId),Employee(Id)"/>

    <Job.Name Element="Job" Field="Name" ReferencePath.Name=" User- Job"/>

    <Job.Descr Element="Job" Field="Descr" ReferencePath.Name=" User- Job"/>

  </User>

 

这里明确指出了RelationshipReferencePath。在未指定的情况:

1.在所有包括<Prime>RelationshipReferencePath中,按 非多对多Relationship、多对多RelationshipReferencePath查找;

2.在不包括<Prime>RelationshipReferencePath中,也按 非多对多Relationship、多对多RelationshipReferencePath查找;

3.试图推导ReferencePath,(只用于ElementQuerier,见Chapter Querying Data

 

修饰(Modify)后,会添加到<User>。这里不再列出修饰(Modify)后的XML

 

至此,最主要的PrimarySchema已经生成(DatabaseSchema是个过渡,主要用来生成PrimarySchema)。

 

针对不同的应用场景,可能需要特定应用场景的PrimarySchema变体。XF通过NamedConfig

 

针对不同的应用,可能需要特定应用的PrimarySchema变体。XF通过NamedConfigPrimarySchema修饰(Modify)得到这个变体,称之为NamedSchema

顾名思义,NamedSchema 必定有一个名称,这个名称就是Name XAttribute属性,显然,这个Name属性来自NamedConfig

一般地,会把所有的NamedConfig放在同一个目录下,XF会根据这些NamedConfig,生成每一个NamedConfig对应的NamedSchema

 

在调用方法时,通过指定SchemaName来取得对应的Schema(不指定、SchemaNamenull或空字符串会取得PrimarySchema)。

 

如果调用方法需要更具个性化,还可以提供一个方法级别的config,即modifying。来修饰上述Schema,形成本次方法调用的Schema