`
lyunabc
  • 浏览: 553759 次
  • 性别: Icon_minigender_2
社区版块
存档分类
最新评论

CodeSmith 使用教程(15) 为Yii Framework 创建生成ActiveRecord的代码模板

 
阅读更多

CodeSmith 使用教程(3): 自动生成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_usertbl_post),一对一( one-to-one 例如tbl_usertbl_profile)和 多对多(many-to-many 例如tbl_categorytbl_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_MANYBELONGS_TOHAS_MANY的组合。 例如,Post属于多个(belongs to many)CategoryCategory有多个(has many)Post.

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

20130107001

CodeSmith 中PLINQO-NH代码位置:

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

20130111001

CodeSmith.SchemaHelper定义的主要类有:

20130111002

几个主要的类为

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

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

20130111003

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

public void Generate()
{
   EntityManager entityManager = CreateEntityManager();
   foreach(IEntity entity in entityManager.Entities)
	{
		if (!(entity is CommandEntity)) {
			RenderEntity(entity);
		}
	}
}

...

private void RenderEntity(IEntity entity)
{

	string folder=@"../models/";
	EntityTemplate entityTemplate = this.Create<EntityTemplate>();
	entityTemplate.SourceEntity = entity;
	entityTemplate.RenderToFile(folder+entity.Name+".php", true);
}
子模板则根据每个Entity的Assoications(关系属性)为AR 生成relations函数,

<?php

class <%= SourceEntity.Name %> extends CActiveRecord
{
	public static function model($className=__CLASS__)
	{
		return parent::model($className);
	}

	public function tableName()
	{
		return '<%= SourceEntity.GetSafeName() %>';
	}

    <%if (SourceEntity.Associations.Count>0){ %>
    public function relations()
	{
		return array(
 		 <% IEnumerable<IAssociation> associations = SourceEntity.Associations; %>
         <% foreach(IAssociation association in associations) { %>
         <% if(association.Entity.Name!=association.ForeignEntity.Name) {%>
            <% if (association.AssociationType == AssociationType.ManyToOne
                || association.AssociationType==AssociationType.ManyToZeroOrOne) { %>
            '<%= ToCameral(association.Name) %>'=>array(self::BELONGS_TO,
			'<%= association.ForeignEntity.Name %>',
			<%=GetBelongToKey(association) %>
            <% } %>
            <% if (association.AssociationType == AssociationType.OneToMany
                || association.AssociationType==AssociationType.ZeroOrOneToMany) { %>
            '<%= ToCameral(association.Name) %>'=>array(self::HAS_MANY,
			'<%= association.ForeignEntity.Name %>',
			<%=GetKey(association) %>
            <% } %>
            <% if (association.AssociationType == AssociationType.OneToOne
                || association.AssociationType==AssociationType.OneToZeroOrOne) { %>
            '<%= ToCameral(association.Name) %>'=>array(self::HAS_ONE,
			'<%= association.ForeignEntity.Name %>',
			<%=GetKey(association) %>
            <% } %>
            <% if (association.AssociationType == AssociationType.ManyToMany) { %>
            '<%= ToCameral(association.Name) %>'=>array(self::MANY_MANY,
			'<%= association.IntermediaryAssociation.Entity.Name %>',
			<%=GetManyToManyKey(association) %>
            <% } %>
         <% } %>
     <% } %>
		);
	}
    <% } %>
}

?>

<script runat="template">

public string ToCameral(string name)
{
    return StringUtil.ToCamelCase(name);
 }

public string GetKey(IAssociation association)
{
    string retString=string.Empty;

    if(association.Properties.Count>1)
    {
        retString="array(";
        foreach (AssociationProperty associationProperty in association.Properties)
        {
            retString+="'"+associationProperty.ForeignProperty.GetSafeName()+"',";
        }
        retString+="),";
    }else{
        foreach (AssociationProperty associationProperty in association.Properties)
        {
            retString+="'"+associationProperty.ForeignProperty.GetSafeName()+"'),";
        }

    }
    return retString;
}

public string GetBelongToKey(IAssociation association)
{
    string retString=string.Empty;

    if(association.Properties.Count>1)
    {
        retString="array(";
        foreach (AssociationProperty associationProperty in association.Properties)
        {
            retString+="'"+associationProperty.Property.GetSafeName()+"',";
        }
        retString+="),";
    }else{
        foreach (AssociationProperty associationProperty in association.Properties)
        {
            retString+="'"+associationProperty.Property.GetSafeName()+"'),";
        }

    }
    return retString;
}

public string GetManyToManyKey(IAssociation association)
{

    string retString="'"+association.ForeignEntity.GetSafeName()+"(";

    foreach (AssociationProperty associationProperty in association.Properties)
    {
        retString+=associationProperty.ForeignProperty.GetSafeName()+",";
    }
    IAssociation intermidateAssociation=association.IntermediaryAssociation;
    if(intermidateAssociation!=null)
    {
           foreach (AssociationProperty associationProperty in intermidateAssociation.Properties)
        {
            retString+=associationProperty.ForeignProperty.GetSafeName()+",";
        }
    }

    retString=retString.Substring(0,retString.Length-1);
    retString+=")'),";
    return retString;
}
</script>

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

class Track extends CActiveRecord
{
	public static function model($className=__CLASS__)
	{
		return parent::model($className);
	}

	public function tableName()
	{
		return 'track';
	}

    public function relations()
	{
		return array(
            'album'=>array(self::BELONGS_TO,'Album','AlbumId'),
            'genre'=>array(self::BELONGS_TO,'Genre','GenreId'),
            'mediatype'=>array(self::BELONGS_TO,'Mediatype','MediaTypeId'),
            'invoicelines'=>array(self::HAS_MANY,'Invoiceline','TrackId'),
            'playlists'=>array(self::MANY_MANY,'Playlist','playlisttrack(TrackId,PlaylistId)'),
		);
	}
}

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

20130111004

本例下载,如果需要使用本例的模板,直接把项目中protected下的codesmith 目录拷贝到你自己的项目中,然后为codesmith.csp 配置数据源(或者还有表前缀),然后生成代码即可。

20130111005

本例下载

分享到:
评论

相关推荐

    CodeSmith使用教程 - v1.01

    CodeSmith 是一款强大的代码生成工具,它通过使用模板语言,类似 ASP.NET 的语法,来自动生成各种编程语言的代码或文本。本教程旨在帮助开发者掌握如何有效地利用 CodeSmith 进行自动化编码工作。 ### 第 1 章:...

    codesmith生成代码模板

    总的来说,codesmith代码模板为开发者提供了强大的代码生成能力,它允许根据项目需求定制模板,生成规范、一致的代码,有助于提升开发效率,降低错误率,使得团队可以更专注于业务逻辑和创新性工作。同时,使用模板...

    CodeSmith的批量生成数据库表创建脚本的模板

    标题"CodeSmith的批量生成数据库表创建脚本的模板"暗示了我们将探讨如何使用CodeSmith的模板功能来自动化生成针对SQL Server数据库的建表语句。在数据库开发过程中,手动为每个表编写CREATE TABLE语句是一项繁琐的...

    CodeSmith 生成工具 6.5 (可生成Nhibernate)

    CodeSmith的灵活性在于,用户不仅可以使用内置的Nhibernate模板,还可以根据项目需求自定义模板,实现特定的代码生成逻辑。例如,如果项目中需要特定的验证规则或扩展属性,可以通过修改模板来满足这些需求。同时,...

    codesmith三层代码模板代码模板

    codesmith三层代码模板代码模板,codesmith三层代码模板代码模板,codesmith三层代码模板代码模板,codesmith三层代码模板代码模板,codesmith三层代码模板代码模板,codesmith三层代码模板代码模板。

    CodeSmith 生成三层模板

    在本案例中,"CodeSmith 生成简单三层和SqlHelper的模板"指的是使用CodeSmith创建了一个能够自动生成三层架构(数据访问层、业务逻辑层、表示层)以及SqlHelper类的模板。 三层架构是一种常见的软件设计模式,主要...

    CodeSmith 使用手册 简易教程

    通过这两个文件的学习,开发者可以全面了解CodeSmith的使用方法,从创建简单的模板到构建复杂的代码生成流程,从而提升开发效率,减少手动编写重复代码的时间。同时,熟练掌握CodeSmith也能帮助团队保持代码一致性,...

    CodeSmith教程[全].pdf CodeSmith教程[全].pdf CodeSmith教程[全].pdf

    CodeSmith教程[全].pdf CodeSmith教程[全].pdf CodeSmith教程[全].pdf CodeSmith教程[全].pdf CodeSmith教程[全].pdf CodeSmith教程[全].pdf CodeSmith教程[全].pdf CodeSmith教程[全].pdf CodeSmith教程[全].pdf ...

    codesmith生成实体类简单模板

    《使用Codesmith生成C#实体类的简易模板详解》 在软件开发过程中,尤其是在与数据库交互的业务逻辑层,实体类的创建是一项繁琐且重复的工作。 Codesmith是一款强大的代码生成工具,它允许开发者通过定制模板来自动...

    CodeSmith开发使用教程资料 pdf

    首先,CodeSmith的核心功能是自定义模板生成代码。模板是用C#语法编写的,允许用户根据需求创建复杂的代码结构。通过模板,你可以生成如实体类、数据访问层、业务逻辑层等各种类型的代码。模板语言支持条件判断、...

    CodeSmith 代码生成教程

    CodeSmith是一款基于模板驱动的代码生成器,它允许开发者使用模板语言来创建自定义的代码片段。通过预定义的模板或自定义模板,CodeSmith可以生成几乎任何类型的代码,包括但不限于数据库访问层、业务逻辑层、实体类...

    codesmith 3层代码生成模板

    总结,Codesmith的3层代码生成模板为开发者提供了强大的工具,使得构建3层架构的系统变得简单而高效。通过熟练掌握和运用这些模板,可以显著提升开发效率,降低维护成本,使开发者更专注于业务创新而非基础代码的...

    Java 代码生成器CodeSmith是一个好工具

    CodeSmith 是一种基于模板的代码生成工具,它使用类似于 ASP.NET 的语法来生成任意类型的代码或文本。与其他许多代码生成工具不同,CodeSmith 不要求您订阅特定的应用程序设计或体系结构。使用 CodeSmith,可以生成...

    CodeSmith基于模板的代码生成工具

    CodeSmith 是一种基于模板的代码生成工具,它使用类似于 ASP.NET 的语法来生成任意类型的代码或文本。与其他许多代码生成工具不同,CodeSmith 不要求您订阅特定的应用程序设计或体系结构。使用 CodeSmith,可以生成...

    CodeSmith开发使用教程资料

     CodeSmith使用教程,开发资料,PDF高清淅版,对CodeSmith熟悉的朋友都知道,CodeSmith是一个基于模板的代码生成工具,它使用类似于ASP.NET的语法来生成代码或文本,本教程将带你掌握CodeSmith的使用方法和原理等...

    CodeSmith .net 三层自动生成模板

    CodeSmith是一款强大的.NET代码生成工具,它允许开发者通过自定义模板快速生成各种代码,从而提高开发效率和代码质量。在.NET 2.0时代,CodeSmith就已经被广泛应用于项目开发中,尤其是对于三层架构(数据访问层、...

    asp.net codeSmith三层代码生成模板

    总之,使用ASP.NET CodeSmith三层代码生成模板可以显著提升开发效率,减少编码错误,并使代码结构更加清晰。开发者可以根据项目需求定制模板,以适应不同的数据库系统和业务场景。不过,值得注意的是,虽然自动化...

    CodeSmith三层代码生成模板

    接着,使用`DBMad.DAL.cst`模板生成数据访问代码,这可能包括数据库连接、SQL语句或ORM映射。最后,`DBMad.BLL.cst`模板则用于生成业务逻辑层的代码,实现业务规则和处理。 总的来说,CodeSmith三层代码生成模板是...

    CodeSmith使用基础教程

    首先,我们从“CodeSmith使用基础教程 一 — 模板”开始。模板是CodeSmith的核心,它定义了生成代码的结构和逻辑。你可以创建自定义模板,以满足特定项目或编程语言的需求。模板可以包含变量、循环、条件语句等,...

    普通 codesmith三层代码生成模板

    "普通 codesmith三层代码生成模板" 是一个专为C#开发者设计的工具,用于自动化生成代码,特别是在开发三层架构的应用程序时。三层架构通常包括表现层(Presentation Layer)、业务逻辑层(Business Logic Layer)和...

Global site tag (gtag.js) - Google Analytics