课程表

CodeSmith课程

工具箱
速查手册

创建生成ActiveRecord模板

当前位置:免费教程 » 软件/图像 » CodeSmith

为 Yii Framework 创建生成 ActiveRecord 的代码模板

CodeSmith :自动生成 Yii Framework ActiveRecord 我们通过 SchemaExploer 为 Yii Framework 从数据库生成简单的 ActiveRecord 类,没有考虑到表和表之间的关系。本例我们使用 CodeSmith 为 Yii Framework 创建一个通用的代码模板,可以使用上例介绍的SchemaExploer ,不过在查看 CodeSmith 自带的例子中有个生成 Hibernate 的例子,这个模板的使用可以参见 CodeSmith 使用教程(1): 概述 ,CodeSmith 提供了这个模板的源码,使用到了 CodeSmith.SchemaHelper (CodeSmith 没有提供相应的文档),不过可以通过阅读 NHiberante 的模板了解其一般用法。

为生成 Yii Framework ActiveRecord 类之间的 relation ,先要了解一下表和表之间的关系:

两个 AR 类之间的关系直接通过 AR 类所代表的数据表之间的关系相关联。 从数据库的角度来说,表 A 和 B 之间有三种关系:一对多(one-to-many,例如 tbl_user 和 tbl_post),一对一( one-to-one 例如 tbl_user 和tbl_profile)和 多对多(many-to-many 例如 tbl_category 和 tbl_post)。 在 AR 中,有四种关系:

  • BELONGS_TO(属于): 如果表 A 和 B 之间的关系是一对多,则 表 B 属于 表 A (例如 Post 属于 User);

  • HAS_MANY(有多个): 如果表 A 和 B 之间的关系是一对多,则 A 有多个 B (例如 User 有多个 Post);

  • HAS_ONE(有一个): 这是 HAS_MANY 的一个特例,A 最多有一个 B (例如 User 最多有一个 Profile);

  • MANY_MANY: 这个对应于数据库中的 多对多 关系。 由于多数 DBMS 不直接支持 多对多 关系,因此需要有一个关联表将 多对多 关系分割为 一对多 关系。 在我们的示例数据结构中,tbl_post_category 就是用于此目的的。在 AR 术语中,我们可以解释 MANY_MANY 为 BELONGS_TO 和 HAS_MANY 的组合。 例如,Post 属于多个(belongs to many) Category ,Category 有多个(has many) Post.

本例还是使用 Chinook 数据库,修改 Yii Framework 开发教程(27) 数据库-关联 Active Record 示例。数据表之间的关系如下:

第26张

CodeSmith 中 PLINQO-NH 代码位置:

缺省目录为 C:\Program Files (x86)\CodeSmith\v6.5\Samples\Templates\Frameworks\PLINQO-NH

第27张

CodeSmith.SchemaHelper 定义的主要类有:

第28张

几个主要的类为

  • EntityManager 管理所有的 Entity(对应于整个数据库)
  • Entity 实体类(对应到单个表,视图)
  • IAssoication 关系(定义表和表之间的关系)
  • AssoicationType 关系的类型 (见下表)

根据 AssociationType ,数据库之间的关系以及 Yii AR 支持的几种关系,可以定义下表:

第29张

整个模板也是采用主-从模板的方式,主模板枚举 EntityManager 中的每个 Entity,然后调用子模板为每个表 生成 AR 类:

  1. public void Generate()
  2. {
  3. EntityManager entityManager = CreateEntityManager();
  4. foreach(IEntity entity in entityManager.Entities)
  5. {
  6. if (!(entity is CommandEntity)) {
  7. RenderEntity(entity);
  8. }
  9. }
  10. }

...

  1. private void RenderEntity(IEntity entity)
  2. {
  3. string folder=@"../models/";
  4. EntityTemplate entityTemplate = this.Create<EntityTemplate>();
  5. entityTemplate.SourceEntity = entity;
  6. entityTemplate.RenderToFile(folder+entity.Name+".php", true);
  7. }

子模板则根据每个 Entity 的 Assoications(关系属性)为 AR 生成 relations 函数,

  1. <?php
  2. class <%= SourceEntity.Name %> extends CActiveRecord
  3. {
  4. public static function model($className=__CLASS__)
  5. {
  6. return parent::model($className);
  7. }
  8. public function tableName()
  9. {
  10. return '<%= SourceEntity.GetSafeName() %>';
  11. }
  12. <%if (SourceEntity.Associations.Count>0){ %>
  13. public function relations()
  14. {
  15. return array(
  16. <% IEnumerable<IAssociation> associations = SourceEntity.Associations; %>
  17. <% foreach(IAssociation association in associations) { %>
  18. <% if(association.Entity.Name!=association.ForeignEntity.Name) {%>
  19. <% if (association.AssociationType == AssociationType.ManyToOne
  20. || association.AssociationType==AssociationType.ManyToZeroOrOne) { %>
  21. '<%= ToCameral(association.Name) %>'=>array(self::BELONGS_TO,
  22. '<%= association.ForeignEntity.Name %>',
  23. <%=GetBelongToKey(association) %>
  24. <% } %>
  25. <% if (association.AssociationType == AssociationType.OneToMany
  26. || association.AssociationType==AssociationType.ZeroOrOneToMany) { %>
  27. '<%= ToCameral(association.Name) %>'=>array(self::HAS_MANY,
  28. '<%= association.ForeignEntity.Name %>',
  29. <%=GetKey(association) %>
  30. <% } %>
  31. <% if (association.AssociationType == AssociationType.OneToOne
  32. || association.AssociationType==AssociationType.OneToZeroOrOne) { %>
  33. '<%= ToCameral(association.Name) %>'=>array(self::HAS_ONE,
  34. '<%= association.ForeignEntity.Name %>',
  35. <%=GetKey(association) %>
  36. <% } %>
  37. <% if (association.AssociationType == AssociationType.ManyToMany) { %>
  38. '<%= ToCameral(association.Name) %>'=>array(self::MANY_MANY,
  39. '<%= association.IntermediaryAssociation.Entity.Name %>',
  40. <%=GetManyToManyKey(association) %>
  41. <% } %>
  42. <% } %>
  43. <% } %>
  44. );
  45. }
  46. <% } %>
  47. }
  48. ?>
  49. <script runat="template">
  50. public string ToCameral(string name)
  51. {
  52. return StringUtil.ToCamelCase(name);
  53. }
  54. public string GetKey(IAssociation association)
  55. {
  56. string retString=string.Empty;
  57. if(association.Properties.Count>1)
  58. {
  59. retString="array(";
  60. foreach (AssociationProperty associationProperty in association.Properties)
  61. {
  62. retString+="'"+associationProperty.ForeignProperty.GetSafeName()+"',";
  63. }
  64. retString+="),";
  65. }else{
  66. foreach (AssociationProperty associationProperty in association.Properties)
  67. {
  68. retString+="'"+associationProperty.ForeignProperty.GetSafeName()+"'),";
  69. }
  70. }
  71. return retString;
  72. }
  73. public string GetBelongToKey(IAssociation association)
  74. {
  75. string retString=string.Empty;
  76. if(association.Properties.Count>1)
  77. {
  78. retString="array(";
  79. foreach (AssociationProperty associationProperty in association.Properties)
  80. {
  81. retString+="'"+associationProperty.Property.GetSafeName()+"',";
  82. }
  83. retString+="),";
  84. }else{
  85. foreach (AssociationProperty associationProperty in association.Properties)
  86. {
  87. retString+="'"+associationProperty.Property.GetSafeName()+"'),";
  88. }
  89. }
  90. return retString;
  91. }
  92. public string GetManyToManyKey(IAssociation association)
  93. {
  94. string retString="'"+association.ForeignEntity.GetSafeName()+"(";
  95. foreach (AssociationProperty associationProperty in association.Properties)
  96. {
  97. retString+=associationProperty.ForeignProperty.GetSafeName()+",";
  98. }
  99. IAssociation intermidateAssociation=association.IntermediaryAssociation;
  100. if(intermidateAssociation!=null)
  101. {
  102. foreach (AssociationProperty associationProperty in intermidateAssociation.Properties)
  103. {
  104. retString+=associationProperty.ForeignProperty.GetSafeName()+",";
  105. }
  106. }
  107. retString=retString.Substring(0,retString.Length-1);
  108. retString+=")'),";
  109. return retString;
  110. }
  111. </script>

然后 generated output 就可以为数据库的表生成对应的 AR 类,比如生成的 Track 类

  1. class Track extends CActiveRecord
  2. {
  3. public static function model($className=__CLASS__)
  4. {
  5. return parent::model($className);
  6. }
  7. public function tableName()
  8. {
  9. return 'track';
  10. }
  11. public function relations()
  12. {
  13. return array(
  14. 'album'=>array(self::BELONGS_TO,'Album','AlbumId'),
  15. 'genre'=>array(self::BELONGS_TO,'Genre','GenreId'),
  16. 'mediatype'=>array(self::BELONGS_TO,'Mediatype','MediaTypeId'),
  17. 'invoicelines'=>array(self::HAS_MANY,'Invoiceline','TrackId'),
  18. 'playlists'=>array(self::MANY_MANY,'Playlist','playlisttrack(TrackId,PlaylistId)'),
  19. );
  20. }
  21. }

如果实在看不懂本例也无所谓,可以直接使用该模板,只要设置数据源 ,如果数据库的表有前缀,比如Wordpress 的表有 wp_ 可以设置表前缀(不是必须的)

第30张

第31张

转载本站内容时,请务必注明来自W3xue,违者必究。
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号