天天看點

ORM映射架構總結--映射橋梁

1.       感言

寫部落格之前先自我吹噓一下,給這些文章來些自我介紹。

半年前自己借用了5個多月的業務時間寫了一個個人ORM映射架構。在之前的博

客中也有過寫過該架構的相關介紹。半年前的那個ORM隻不過是自己想象的關系映射的一個雛形,那一段曾經讓自己驕傲過得代碼的确存在着太多的問題,但是我始終沒有放棄過對它的修改。又過了半年,這個ORM映射架構在之前的基礎上有了很大的改進。在此與大家分享一下,希望大家共同探讨,共同學習。

2.       架構整體介紹

說道這裡,其實這個ORM架構仍然存在這很大的問題。不過這個是自己的第二期目标,到現在這個程度算是完成了.

目前出現的ORM 架構還是比較多的。本人寫這個ORM不是為了說要推翻某個理論或者要和Linq,Nhibernate 一教高下,目前一個人之力幾乎不可能。寫此架構隻是為了更近一步的了解程式架構。

設計思路其實很簡單,和其餘的ORM架構一樣。通過某種關系來維持實體對象和資料庫之間的關系,然後通過實體對象的操作來實作資料庫的操作。

ORM是通過使用描述對象和資料庫之間映射的中繼資料,在我們想到描述的時候自然就想到了xml和特性(Attribute).目前的ORM架構中,Nhibernate 就是典型的使用xml檔案作為描述實體對象的映射架構,而大名鼎鼎的Linq 則是使用特性(Attribute) 來描述的。

    我自己寫的這個出于學習特性這一知識,于是采用了特性(Attribute)來描述實體對象。

ORM 映射功能的實作組要由如下幾個組建組成:

(1)      

實體—資料庫

映射特性關系

(2)      

實體分析器

(3)      

Sql 語句生成組建

(4)      

資料庫操作庫

架構整體結構圖:

3.       實體—資料庫映射特性

對于資料庫和實體之間關系的描述,這個架構中使用了四個特性來描述。

TableAttribute 特性

字段名

作用

name

資料表名

該字段用于描述資料庫對應表的名稱,而且該值最好與

資料表名大小寫相同。該值有兩種類型。

(1)直接自定表的名稱

(2)[資料庫名].[表名]

如果是(2)情況,則需要分割字元串,将資料庫名分割

出來指派給dBName

dBName

資料庫名

該字段用于描述資料的名稱,而且該值最好與

資料庫名稱大小寫相同

primaryKeyName

主鍵字段名

該實體必須指定對應資料庫表的主鍵

information

表實體描述資訊

預設為""

isInternal

表實體是否國際化

預設為false

true 國際化 false 不國際化

version

表實體版本号

預設為

"V1.0"

特性源碼:

    1 /**

  2  * 2010-1-28

  3  * 

  4  * 情 緣

  5  * 

  6  * 實體表特性,用于描述實體和資料庫表之間的映射關系

  7  * 

  8  * 該特性類使用 sealed 修改,說明該類不能夠再被繼承。

  9  * 

 10  * */

 11 

 12 using System;

 13 

 14 namespace CommonData.Model.Core

 15 {

 16     public sealed class TableAttribute:Attribute

 17     {

 18         /// <summary>

 19         /// 資料表名

 20         /// 該字段用于描述資料庫對應表的名稱,而且該值最好與

 21         /// 資料表名大小寫相同。該值有兩種類型。

 22         /// (1)直接自定表的名稱

 23         /// (2)[資料庫名].[表名]

 24         /// 如果是(2)情況,則需要分割字元串,将資料庫名分割

 25         /// 出來指派給dBName

 26         /// </summary>

 27         private string name;

 28 

 29         /// <summary>

 30         /// 資料庫名

 31         /// 該字段用于描述資料的名稱,而且該值最好與

 32         /// 資料庫名稱大小寫相同

 33         /// </summary>

 34         private string dBName;

 35 

 36         /// <summary>

 37         /// 主鍵字段名

 38         /// 該實體必須指定對應資料庫表的主鍵

 39         /// </summary>

 40         private string primaryKeyName = "";

 41 

 42         /// <summary>

 43         /// 表實體描述資訊

 44         /// 預設為""

 45         /// </summary>

 46         private string information = "";

 47 

 48         /// <summary>

 49         /// 表實體是否國際化

 50         /// 預設為false

 51         /// true 國際化 false 不國際化

 52         /// </summary>

 53         private bool isInternal = false;

 54 

 55         /// <summary>

 56         /// 表實體版本号

 57         /// 預設為 "V1.0"

 58         /// </summary>

 59         private string version = "V1.0";

 60 

 61 

 62         /// <summary>

 63         /// 無參數構造方法

 64         /// </summary>

 65         public TableAttribute()

 66         {

 67 

 68         }

 69 

 70         /// <summary>

 71         /// 部分參數構造方法,構造改表特性的實體類

 72         /// 并實作部分字段的初始化

 73         /// </summary>

 74         /// <param name="name">資料表名</param>

 75         /// <param name="dBName">資料庫名</param>

 76         /// <param name="primaryKeyName">主鍵字段名</param>

 77         /// <param name="isInternal">表實體是否國際化</param>

 78         public TableAttribute(string name, 

 79             string dBName, 

 80             string primaryKeyName, 

 81             bool isInternal) 

 82         {

 83             this.name = name;

 84             this.dBName = dBName;

 85             this.primaryKeyName = primaryKeyName;

 86             this.isInternal = isInternal;

 87         }

 88 

 89         /// <summary>

 90         /// 全參數構造方法,構造改表特性的實體類

 91         /// 并實作所有字段的初始化

 92         /// </summary>

 93         /// <param name="name">資料表名</param>

 94         /// <param name="dBName">資料庫名</param>

 95         /// <param name="primaryKeyName">主鍵字段名</param>

 96         /// <param name="information">表實體描述資訊</param>

 97         /// <param name="isInternal">表實體是否國際化</param>

 98         /// <param name="version">表實體版本号</param>

 99         public TableAttribute(string name, 

100             string dBName, 

101             string primaryKeyName, 

102             string information, 

103             bool isInternal, 

104             string version)

105         {

106             this.name = name;

107             this.dBName = dBName;

108             this.primaryKeyName = primaryKeyName;

109             this.information = information;

110             this.isInternal = isInternal;

111             this.version = version;

112         }

113 

114         /// <summary>

115         /// 資料表名

116         /// </summary>

117         public string Name

118         {

119             get { return name; }

120             set { name = value; }

121         }

122         

123         /// <summary>

124         /// 資料庫名

125         /// </summary>

126         public string DBName

127         {

128             get { return dBName; }

129             set { dBName = value; }

130         }

131         

132         /// <summary>

133         /// 主鍵字段名

134         /// </summary>

135         public string PrimaryKeyName

136         {

137             get { return primaryKeyName; }

138             set { primaryKeyName = value; }

139         }

140         

141         /// <summary>

142         /// 表實體描述資訊

143         /// </summary>

144         public string Information

145         {

146             get { return information; }

147             set { information = value; }

148         }

149         

150         /// <summary>

151         /// 表實體是否國際化

152         /// </summary>

153         public bool IsInternal

154         {

155             get { return isInternal; }

156             set { isInternal = value; }

157         }

158         

159         /// <summary>

160         /// 表實體版本号

161         /// </summary>

162         public string Version

163         {

164             get { return version; }

165             set { version = value; }

166         }

167 

168         

169     }

170 }

171 

  特性說明:實體表特性,用于描述實體和資料庫表之間的映射關系,該特性類使用 sealed 修改,說明該類不能夠再被繼承。

ColumnAttribute特性

表字段名稱,該屬性的值最好與資料表的字段的名稱相同。

該字段的值有兩種格式:

(1) [表名].[字段名]

(2) [字段名]

如果該字段的值為(1)情況,則應分割字元串,将字段名

指派給name屬性,表名則指派給tableName

tableName

表字段對應表名稱

該值是可以為空的,如果name的值的情況滿足(1)情況,

可以分割的值指派給該屬性

dataType

表字段的資料類型

該屬性的類型為自定義類型,該字段是一個枚舉類型。

該字段描述了25中資料類型

length

表字段的長度

控制該字段對應的資料庫表字段值的最大長度

可以不指定該值

canNull

表字段是否可以為空

true 可以為空

false 不能為空

defaultValue

表字段的預設值

預設情況為null

isPrimaryKey

表字段是否為主鍵

true  為主鍵

false 不是外鍵

autoIncrement

表字段是否為自動增長列

true  是自動增長列

false 不是自動增長列

isUnique

确定某個字段是否唯一

true  是唯一的

false 不是唯一

regularExpress

表字段的比對規則

字段比對規則正規表達式

isForeignKey

表字段是否為外鍵

true  為外鍵

foreignTabName

表字段外鍵對應的表名稱

如果isForeignKey

為true,則需要指定其值

表字段的描述資訊

 特性源碼:

   1 /**

  6  * 實體表特性,用于描述實體字段和資料庫表字段之間的映射關系

 16     public sealed class ColumnAttribute:Attribute

 19         /// 表字段名稱,該屬性的值最好與資料表的字段的名稱相同。

 20         /// 該字段的值有兩種格式:

 21         /// (1) [表名].[字段名] 

 22         /// (2) [字段名]

 23         /// 如果該字段的值為(1)情況,則應分割字元串,将字段名

 24         /// 指派給name屬性,表名則指派給tableName

 25         /// </summary>

 26         private string name;

 27 

 28         /// <summary>

 29         /// 表字段對應表名稱

 30         /// 該值是可以為空的,如果name的值的情況滿足(1)情況,

 31         /// 可以分割的值指派給該屬性

 32         /// </summary>

 33         private string tableName;

 34 

 35         /// <summary>

 36         /// 表字段的資料類型

 37         /// 該屬性的類型為自定義類型,該字段是一個枚舉類型。

 38         /// 該字段描述了25中資料類型

 40         private DataType dataType;

 43         /// 表字段的長度

 44         /// 控制該字段對應的資料庫表字段值的最大長度

 45         /// 可以不指定該值

 46         /// </summary>

 47         private int length;

 48 

 49         /// <summary>

 50         /// 表字段是否可以為空

 51         /// true 可以為空

 52         /// false 不能為空

 53         /// </summary>

 54         private bool canNull;

 55 

 56         /// <summary>

 57         /// 表字段的預設值

 58         /// 預設情況為null

 59         /// </summary>

 60         private object defaultValue;

 63         /// 表字段是否為主鍵

 64         /// true  為主鍵

 65         /// false 不是外鍵

 66         /// </summary>

 67         private bool isPrimaryKey = false;

 68 

 69         /// <summary>

 70         /// 表字段是否為自動增長列

 71         /// true  是自動增長列

 72         /// false 不是自動增長列

 74         private bool autoIncrement = false;

 75 

 76         /// <summary>

 77         /// 确定某個字段是否唯一

 78         /// true  是唯一的

 79         /// false 不是唯一

 80         /// </summary>

 81         private bool isUnique;

 82 

 83         /// <summary>

 84         /// 表字段的比對規則

 85         /// 字段比對規則正規表達式

 86         /// </summary>

 87         private string regularExpress;

 90         /// 表字段是否為外鍵

 91         /// true  為外鍵

 92         /// false 不是外鍵

 93         /// </summary>

 94         private bool isForeignKey=false;

 95 

 96         /// <summary>

 97         /// 表字段外鍵對應的表名稱

 98         /// 如果isForeignKey 為true,則需要指定其值

 99         /// </summary>

100         private string foreignTabName;

101 

102         /// <summary>

103         /// 表字段的描述資訊

104         /// </summary>

105         private string information;

106 

107 

108         /// <summary>

109         /// 無參數構造方法

110         /// </summary>

111         public ColumnAttribute()

112         { 

113         }

114 

115         /// <summary>

116         /// 部分參數構造方法,構造該特性執行個體時

117         /// 初始化部分實體屬性的值

118         /// </summary>

119         /// <param name="name">表字段名稱</param>

120         /// <param name="dataType">表字段的資料類型</param>

121         /// <param name="isPrimaryKey">表字段是否為主鍵</param>

122         /// <param name="autoIncrement">表字段是否為自動增長列</param>

123         /// <param name="isUnique">确定某個字段是否唯一</param>

124         /// <param name="isForeignKey">表字段是否為外鍵</param>

125         /// <param name="foreignTabName">表字段外鍵對應的表名稱</param>

126         public ColumnAttribute(string name,

127             DataType dataType,

128             bool isPrimaryKey,

129             bool autoIncrement,

130             bool isUnique,

131             bool isForeignKey,

132             string foreignTabName)

133         {

134             this.name = name;

135             this.dataType = dataType;

136             this.isPrimaryKey = isPrimaryKey;

137             this.autoIncrement = autoIncrement;

138             this.isUnique = isUnique;

139             this.isForeignKey = isForeignKey;

140             this.foreignTabName = foreignTabName;

141         }

142 

143         /// <summary>

144         /// 全部參數構造方法,構造該特性執行個體時

145         /// 初始化全部實體屬性的值

146         /// </summary>

147         /// <param name="name">表字段名稱</param>

148         /// <param name="tableName">表字段對應表名稱</param>

149         /// <param name="dataType">表字段的資料類型</param>

150         /// <param name="length">表字段的長度</param>

151         /// <param name="canNull">表字段是否可以為空</param>

152         /// <param name="defaultValue">表字段的預設值</param>

153         /// <param name="isPrimaryKey">表字段是否為主鍵</param>

154         /// <param name="autoIncrement">表字段是否為自動增長列</param>

155         /// <param name="isUnique">确定某個字段是否唯一</param>

156         /// <param name="regularExpress">表字段的比對規則</param>

157         /// <param name="isForeignKey">表字段是否為外鍵</param>

158         /// <param name="foreignTabName">表字段外鍵對應的表名稱</param>

159         /// <param name="information">表字段的描述資訊</param>

160         public ColumnAttribute(string name,

161             string tableName,

162             DataType dataType,

163             int length,

164             bool canNull,

165             object defaultValue,

166             bool isPrimaryKey,

167             bool autoIncrement,

168             bool isUnique,

169             string regularExpress,

170             bool isForeignKey,

171             string foreignTabName,

172             string information)

173         {

174             this.name = name;

175             this.tableName = tableName;

176             this.dataType = dataType;

177             this.length = length;

178             this.canNull = canNull;

179             this.defaultValue = defaultValue;

180             this.isPrimaryKey = isPrimaryKey;

181             this.autoIncrement = autoIncrement;

182             this.regularExpress = regularExpress;

183             this.isForeignKey = isForeignKey;

184             this.ForeignTabName = foreignTabName;

185             this.information = information;

186             this.isUnique = isUnique;

187         }

188 

189         /// <summary>

190         /// 表字段名稱

191         /// </summary>

192         public string Name

193         {

194             get { return name; }

195             set { name = value; }

196         }

197         

198         /// <summary>

199         /// 表字段對應表名稱

200         /// </summary>

201         public string TableName

202         {

203             get { return tableName; }

204             set { tableName = value; }

205         }

206         

207         /// <summary>

208         /// 表字段的資料類型

209         /// </summary>

210         public DataType DataType

211         {

212             get { return dataType; }

213             set { dataType = value; }

214         }

215         

216         /// <summary>

217         /// 表字段的長度

218         /// </summary>

219         public int Length

220         {

221             get { return length; }

222             set { length = value; }

223         }

224         

225         /// <summary>

226         /// 表字段是否可以為空

227         /// </summary>

228         public bool CanNull

229         {

230             get { return canNull; }

231             set { canNull = value; }

232         }

233         

234         /// <summary>

235         /// 表字段的預設值

236         /// </summary>

237         public object DefaultValue

238         {

239             get { return defaultValue; }

240             set { defaultValue = value; }

241         }

242         

243         /// <summary>

244         /// 表字段是否為主鍵

245         /// </summary>

246         public bool IsPrimaryKey

247         {

248             get { return isPrimaryKey; }

249             set { isPrimaryKey = value; }

250         }

251         

252         /// <summary>

253         /// 表字段是否為自動增長列

254         /// </summary>

255         public bool AutoIncrement

256         {

257             get { return autoIncrement; }

258             set { autoIncrement = value; }

259         }

260         

261         /// <summary>

262         /// 表字段的比對規則

263         /// </summary>

264         public string RegularExpress

265         {

266             get { return regularExpress; }

267             set { regularExpress = value; }

268         }

269         

270         /// <summary>

271         /// 表字段是否為外鍵

272         /// </summary>

273         public bool IsForeignKey

274         {

275             get { return isForeignKey; }

276             set { isForeignKey = value; }

277         }

278         

279         /// <summary>

280         /// 表字段外鍵對應的表名稱

281         /// </summary>

282         public string ForeignTabName

283         {

284             get { return foreignTabName; }

285             set { foreignTabName = value; }

286         }

287         

288         /// <summary>

289         /// 表字段的描述資訊

290         /// </summary>

291         public string Information

292         {

293             get { return information; }

294             set { information = value; }

295         }

296 

297         /// <summary>

298         /// 确定某個字段是否唯一

299         /// </summary>

300         public bool IsUnique

301         {

302             get { return isUnique; }

303             set { isUnique = value; }

304         }

305     }

306 }

307 

  特性說明:實體表特性,用于描述實體字段和資料庫表字段之間的映射關系,該特性類使用 sealed 修改,說明該類不能夠再被繼承。

LinkTableAttribute 特性

該實體屬性對應的資料庫表名

sqlPrefix

該實體屬性對應的資料庫表名字首

一般情況下沒有太大意思

該實體屬性對應的資料類型

可以通過發射獲得類型

keyName

該實體對應的主鍵類型

(用資料的列名來表示,不要使用實體的屬性來定義)

className

對應的實體的全路徑類型

isLazy

對應的實體是否延長加載

  1 /**

  6  * 實體屬性特性,用于描述某個實體作為另外一個實體

  7  * 的一個屬性字段的時候與資料庫表之間的關系

  8  *

  9  * 這個實體特性類和其餘的幾個有差別,沒有用sealed 

 10  * 修飾,因為這個特性是用于修飾實體屬性的,而實體屬

 11  * 性的集合也是一種特殊的屬性,是以可以使用

 12  * LinkTablesAttribute 來繼承該特性。兩者在屬性描述

 13  * 上基本沒有太大的差別

 14  * 

 15  * */

 16 

 17 using System;

 18 

 19 

 20 namespace CommonData.Model.Core

 21 {

 22     public class LinkTableAttribute:Attribute

 23     {

 24         /// <summary>

 25         /// 該實體屬性對應的資料庫表名

 30         /// 該實體屬性對應的資料庫表名字首

 31         /// 一般情況下沒有太大意思

 33         private string sqlPrefix;

 36         /// 該實體屬性對應的資料類型

 37         /// 可以通過發射獲得類型

 38         /// </summary>

 39         private Type dataType;

 40 

 41         /// <summary>

 42         /// 該實體對應的主鍵類型

 43         /// (用資料的列名來表示,不要使用實體的屬性來定義)

 44         /// </summary>

 45         private string keyName;

 46 

 47         /// <summary>

 48         /// 對應的實體的全路徑類型

 49         /// </summary>

 50         private string className;

 51 

 52         /// <summary>

 53         /// 對應的實體是否延長加載

 54         /// </summary>

 55         private bool isLazy;

 56 

 57         /// <summary>

 58         /// 無參數構造方法

 60         public LinkTableAttribute()

 61         { 

 62         }

 63 

 64         /// <summary>

 65         /// 部分參數構造方法,構造該特性執行個體的時候

 66         /// 初始化部分屬性

 67         /// </summary>

 68         /// <param name="name">該實體屬性對應的資料庫表名</param>

 69         /// <param name="dataType">該實體屬性對應的資料類型</param>

 70         /// <param name="keyName">該實體對應的主鍵類型</param>

 71         /// <param name="className">對應的實體的全路徑類型</param>

 72         public LinkTableAttribute(string name, Type dataType, string keyName, string className)

 73         {

 74             this.name = name;

 75             this.dataType = dataType;

 76             this.keyName = keyName;

 77             this.className = className;

 78         }

 79 

 80         /// <summary>

 81         /// 全參數構造方法,構造該特性執行個體的時候

 82         /// 初始化全部屬性

 83         /// </summary>

 84         /// <param name="name">該實體屬性對應的資料庫表名</param>

 85         /// <param name="sqlPrefix">該實體屬性對應的資料庫表名字首</param>

 86         /// <param name="dataType">該實體屬性對應的資料類型</param>

 87         /// <param name="keyName">該實體對應的主鍵類型</param>

 88         /// <param name="className">對應的實體的全路徑類型</param>

 89         public LinkTableAttribute(string name,string sqlPrefix, Type dataType, string keyName, string className)

 90         {

 91             this.name = name;

 92             this.sqlPrefix = sqlPrefix;

 93             this.dataType = dataType;

 94             this.keyName = keyName;

 95             this.className = className;

 96         }

 97 

 98         public string Name

 99         {

100             get { return name; }

101             set { name = value; }

102         }

103 

104         

105         public string SqlPrefix

106         {

107             get { return sqlPrefix; }

108             set { sqlPrefix = value; }

109         }

110 

111         

112         public Type DataType

113         {

114             get { return dataType; }

115             set { dataType = value; }

116         }

117 

118         

119         public string KeyName

120         {

121             get { return keyName; }

122             set { keyName = value; }

123         }

124 

125         

126         public string ClassName

128             get { return className; }

129             set { className = value; }

131 

132         public bool IsLazy

134             get { return isLazy; }

135             set { isLazy = value; }

136         }

137     }

138 }

139 

  特性說明:實體屬性特性,用于描述某個實體作為另外一個實體的一個屬性字段的時候與資料庫表之間的關系.這個實體特性類和其餘的幾個有差別,沒有用sealed 修飾,因為這個特性是用于修飾實體屬性的,而實體屬 性的集合也是一種特殊的屬性,是以可以使用LinkTablesAttribute 來繼承該特性。兩者在屬性描述上基本沒有太大的差別

LinkTablesAttribute 特性

ORM映射架構總結--映射橋梁

代碼

 1 /**

 2  * 2010-1-28

 3  * 

 4  * 情 緣

 5  * 

 6  * 實體集合屬性特性,用于描述某個實體作為另外一個實體

 7  * 的一個集合屬性的時候與資料庫表之間的關系

 8  * 

 9  * 這個特性使用了 sealed 修飾,說明該特性類不能再被繼

10  * 承。但是這個實體類不是在繼承Attribute,而是繼承

11  * LinkTableAttribute。因為這兩者描述的屬性具有相同的

12  * 特性。隻需要讓它繼承LinkTableAttribute 保留父類的

13  * 屬性就可以了。 LinkTablesAttribute,LinkTableAttribute

14  * 這兩個特性類具有相同的屬性,使用不同的類名隻是為了

15  * 區分修飾的屬性形态有所不同

16  * 

17  * */

18 

19 using System;

20 

21 namespace CommonData.Model.Core

22 {

23     public sealed class LinkTablesAttribute:LinkTableAttribute

24     {

25         /// <summary>

26         /// 無參數構造方法

27         /// </summary>

28         public LinkTablesAttribute()

29         {

30         }

31 

32         /// <summary>

33         /// 部分參數構造方法,構造該特性執行個體的時候,

34         /// 初始化部分屬性,并且調用的是父類的構造

35         /// 方法

36         /// </summary>

37         /// <param name="name">該實體屬性對應的資料庫表名</param>

38         /// <param name="dataType">該實體屬性對應的資料類型</param>

39         /// <param name="keyName">該實體對應的主鍵類型</param>

40         /// <param name="className">對應的實體的全路徑類型</param>

41         public LinkTablesAttribute(string name, Type dataType, string keyName, string className)

42             : base(name,dataType,keyName,className)

43         { }

44 

45 

46         /// <summary>

47         /// 全參數構造方法,構造該特性執行個體的時候

48         /// 初始化全部屬性 ,并且調用的是父類的構造

49         /// 方法

50         /// </summary>

51         /// <param name="name">該實體屬性對應的資料庫表名</param>

52         /// <param name="sqlPrefix">該實體屬性對應的資料庫表名字首</param>

53         /// <param name="dataType">該實體屬性對應的資料類型</param>

54         /// <param name="keyName">該實體對應的主鍵類型</param>

55         /// <param name="className">對應的實體的全路徑類型</param>

56         public LinkTablesAttribute(string name, string sqlPrefix, Type dataType, string keyName, string className)

57             :base(name,sqlPrefix,dataType,keyName,className)

58         { 

59         

60         }

61     }

62 }

63 

 特性說明:實體集合屬性特性,用于描述某個實體作為另外一個實體的一個集合屬性的時候與資料庫表之間的關系

這個特性使用了 sealed 修飾,說明該特性類不能再被繼承。但是這個實體類不是在繼承Attribute,而是繼承LinkTableAttribute。 因為這兩者描述的屬性具有相同的特性。隻需要讓它繼承LinkTableAttribute 保留父類的屬性就可以了。 LinkTablesAttribute,LinkTableAttribute這兩個特性類具有相同的屬性,使用不同的類名隻是為了區分修飾的屬性形态有所不同

(注: ORM涉及内容比較多,後續期待。本文隻是一個開端,有興趣的可以與本人探讨)