May 25, 2021 CodeSmith
In CodeSmith using tutorial (3): Autogenerate Yii Framework ActiveRecord We use SchemaExploer to generate a simple ActiveRecord class from the database for Yii Framework without taking into account the relationship between tables and tables. In this example, we used CodeSmith to create a generic code template for Yii Framework, using the SchemaExploer described in the example above, but in the example that came with CodeSmith, there is an example of generating Hibernate, which can be found in the CodeSmith Usage Tutorial (1): Overview, CodeSmith provides the source code for this template, and codeSmith.SchemaHelper (CodeSmith does not provide the appropriate documentation), but you can learn about the general usage by reading the CodeSmith template.
To build a relation between the Yii Framework ActiveRecord classes, first look at the relationship between tables and tables:
The relationship between the two AR classes is directly related through the relationship between the data tables represented by the AR class. F rom a database perspective, there are three relationships between Table A and B: one-to-many (one-to-many, for example, tbl_user and tbl_post), one-to-one (one-to-one for example, tbl_user and tbl_profile), and many-to-many (for example, tbl_category and tbl_post). In AR, there are four relationships:
BELONGS_TO (belongs to): If the relationship between Table A and B is one-to-many, Table B belongs to Table A (for example Post belongs to User);
HAS_MANY (multiple): If the relationship between Table A and B is one-to-many, A has more than one B (for example, User has more than One Post);
HAS_ONE (one): This is HAS_MANY exception to the HAS_MANY, A has up to one B (for example, User has up to one Profile);
This example is also using the Chinook database to modify the Yii Framework Development Tutorial (27) Database-Associated Active Record sample. The relationships between the data sheets are as follows:
PLINQO-NH code location in CodeSmith:
The default directory is C:\Program Files (x86)\CodeSmith\v6.5\Samples\Templates\Frameworks\PLINQO-NH
The main classes defined by CodeSmith.SchemaHelper are:
Several major classes are
Based on AssociationType, the relationships between databases, and several relationships supported by Yii AR, you can define the following table:
The entire template is also master-from-template, enumerateing each Enterprise in EnterpriseManager, and then calling sub-templates to generate AR classes for each table:
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);
}
Sub-templates generate relations functions for AR based on each Enterprise's Assoications (relationship properties).
<?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>
The generated output can then generate a corresponding AR class for the table of the database, such as the generated Track class
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)'),
);
}
}
If you really don't understand this example also doesn't matter, you can use the template directly, as long as you set the data source, if the database table has a prefix, such as Wordpress table has wp_ you can set the table prefix (not required)
This example Download if you need to use the template in this example, copy the codesmith directory under project protected directly into your own project, configure the data source (or table prefix) for codesmith.csp, and generate code.
This example Downloads