Archive
Using the SQL Server Template Producer to generate Clustered Indexes
In this post we’ll see how using CodeFluent Entities’ SQL Server Template Producer, you can generate SQL scripts using the built-in template engine whilst accessing the inferred meta-model, and then automatically deploy the generated script on your desired server.
By default SQL Azure and SQL Server add the clustered index on the primary key if a clustered index on the table does not already exist and if you do not specify a unique nonclustered index. In the case where the primary key is of GUID type it won’t be efficient. The reason for this is that GUIDs are generated in non-sequential order and SQL Server orders a clustered index sequentially. It will work – SQL Server will let you build a clustered index around a unique identifier column, however it will cause the SQL Server to do unnecessary work and cause performance slowdowns.
That being said, what we can do is using the SQL Template Producer to remove all inefficient clustered indexes and recreate them on the right columns. Let’s even go a bit further and create a little aspect that will add a property on each property to tell if a clustered index needs to be created or not on that particular property.
Add a new Part called IsClusteredIndexAspect and past it the following code (replacing the defaultNamespace’s value by yours):
<cf:project xmlns:cf=”http://www.softfluent.com/codefluent/2005/1” defaultNamespace=”yourNamespace”>
<cf:pattern name=”IsClusteredIndex Aspect” namespaceUri=”http://www.sample.com/aspects/isclusteredindexaspect/2012/11” preferredPrefix=”sa” step=”Tables”>
<cf:message class=”_doc”>
This aspect creates an extra IsClusteredIndex bool property on every property.
</cf:message><cf:descriptor name=”IsClusteredIndex” typeName=”boolean” targets=”Property” defaultValue=”false” displayName=”IsClusteredIndex” description=”Should the IsClusteredIndex Aspect apply to this property?” />
</cf:pattern>
</cf:project>
This will create our aspect and add a IsClusteredIndex property on each property in the “Aspects and Producers” property grid:
You can by now choose which property you want to use as a clustered index. Obviously this property should be set to true only on one property by entity since clustered index cannot be applied on several columns.
Now let’s write a script that will remove all clustered indexes and then create new ones based on the columns selected thanks to our aspect. In a file called “[Template]CreateIndexes.sql” add it the following code (Note that this code is only an illustration for this post, it does not take into account constraints, primary keys and so on):
[%@ namespace name="CodeFluent.Model"%]
[%@ namespace name="CodeFluent.Model.Persistence"%]
[%@ namespace name="CodeFluent.Producers.SqlServer"%]
/* [%=Producer.GetSignature()%] */
[%foreach (Entity e in Producer.Project.Entities)
{%]
--remove any existing clustered index on e.Table.FullName
--[...]
[%foreach (Property p in e.Properties)
{
if (p.GetAttributeValue("sa:IsClusteredIndex", false))
{%]
--create your index such as:
CREATE CLUSTERED INDEX [CL_[%=p.Entity.Table.Name%]] ON [%=p.Entity.Table.FullName%] ([[%=p.Column.Name%]]);
GO
[%}
}
}%]
Create a folder called “Template” under the file folder of your CodeFluent Entities project:
Right click on that folder and choose “Add existing item” then browse to your template file and select it.
Now in your CodeFluent Entities project, add an instance of the SQL Server Template Producer with your Template directory as the “Source Directory” and set the “Target Directory” to the project of you choice and then build over your model. The SQL Server Template Producer will generate a script file from your template, and run the script on the server removing and creating clustered indexes. Therefore using the template producer you can quickly create complex scripts by taking advantage of the meta model.
Cheers,
Thibault NESTOR
CodeFluent Entities: Writing a custom aspect
In the previous post, we’ve seen that CodeFluent Entities infers a meta-model from our model and that we could interact with this meta-model to apply application wide changes. In this post we’ll see how ![]()
Step 1: Writing your aspect
As an example we’ll write an aspect which will add a “IsDeleted” property on all entities by default.
First of all, we added a new class library project named “Demo.Aspects” to our solution and added the following references: CodeFluent.Model.dll, CodeFluent.Model.Common.dll and CodeFluent.Runtime.dll. Aspects can either be written in XML or in .NET. In my opinion, it’s easier to start writing aspects in .NET as you’ll have Visual Studio’s IntelliSense which will help you out using the API.
In practice, an aspect is a class implementing the IProjectTemplate interface. This interface contains a single method “Run” which takes as a parameter a “context”.
Here’s a sample implementation:
using System.Collections;
using System.Xml;
using CodeFluent.Model;
namespace Demo.Aspects
{
public class MyAspect: IProjectTemplate
{
public static readonly XmlDocument Descriptor;
public const string MyAspectNamespace = "http://www.mycompany.com/aspects/myaspect/2013/1";
static MyAspect()
{
Descriptor = new XmlDocument();
Descriptor.LoadXml(
@"<cf:project xmlns:cf='http://www.softfluent.com/codefluent/2005/1' defaultNamespace='MyAspect'>
<cf:pattern name='My Aspect' namespaceUri='" + MyAspectNamespace + @"' preferredPrefix='mya' step='Tables'>
<cf:message class='_doc'>This is some description for our custom aspect.</cf:message>
<cf:descriptor name='enable'
typeName='boolean'
category='My Custom Aspect'
targets='Entity'
defaultValue='false'
displayName='Add the MyCustomProperty'
description='Description for our custom descriptor.' />
</cf:pattern>
</cf:project>");
}
public XmlDocument Run(IDictionary context)
{
if (context == null || !context.Contains("Project"))
{
// we are probably called for meta data inspection
return Descriptor;
}
// the dictionary contains at least these two entries
Element = (XmlElement)context["Element"];
Project = (Project)context["Project"];
foreach (Entity entity in Project.Entities)
{
Property property = new Property();
property.Name = "IsDeleted";
property.TypeName = "bool";
entity.Properties.Add(property);
}
// we have no specific Xml to send back, but aspect description
return Descriptor;
}
}
The method returns a XmlDocument which is described above as a string. It could also be written on a separate file.
As you can see this XML defines the aspect’s name, its XML namespace, and how it extends the CodeFluent schema (here it adds a “mya:enable” attribute on entities, whose default value is false).
Step 2: Using your aspect
Compile the “Demo.Aspects” project.
In the solution explorer, select the “Aspects” folder and click “Add Existing Aspect…”. Browse for our Demo.Aspects.dll that we created previously and here’s what you should see:
Great! As you can see, information returned by our descriptor is properly parsed and displayed ![]()
Hit OK, and now by default all your entities should have an extra “IsDeleted” property added when the model is inferred, which means that a “IsDeleted” column will be created for all tables, all stored procedures will be updated to include this column, and it’s the same in the middle tier and the UI tier. You can view this by clicking on the “View Inferred Model” button available in the ribbon:
Useful Links
- Documentation: Aspects Overview
- Documentation: The CodeFluent Entities API
- Documentation: Writing an aspect (.NET)
Hope this helps,
Carl Anderson
New CodeFluent Entities Version Released!
A new CodeFluent Entities version (646) has been released and is publicly available!
You can download it from here: CodeFluent Entities Download Page.
Enhanced Visual Studio 11 Beta integration
Remember the “CodeFluent Entities & Visual Studio 11 Beta” post? Well we kept our word and corrected the glitches ![]()
SQL Server 2012 is supported by the SQL Server Producer
More details in this post: Added SQL Server 2012 Support
Enumeration declarations now support named values
You can now do stuff with multi-valued enumerations such as (supported separators are , ; | and +):
<cf:enumeration name="WeekDays" multivalue="true" >
<None />
<Sunday />
<Monday />
<Tuesday />
<Wednesday />
<Thursday />
<Friday />
<Saturday />
<WeekDays value="Monday,Tuesday,Wednesday,Thursday,Friday" />
</cf:enumeration>
(Thank you GregD for the suggestion)
Project Level “Implements” and “Set Implements” rules
You can define “Implements” and “Set Implements” rules at project level so all generated classes implement a specific interface or derive from a specific class (http://forums.softfluent.com/default.aspx?g=posts&t=395).
Transaction rules
Transaction rules can now be added on methods other than Save and Delete, including custom ones. Developers don’t have to write the TransactionScope code themselves when adding a new custom method: all it takes is selecting your method and add a transaction rule on it ![]()
The Modeler now supports Aspect assemblies
If you are familiar with CodeFluent Aspects, you already know that you can develop aspects in XML or in .NET assemblies.
You’ll be glad to know that the Modeler now fully supports .NET assemblies including assemblies containing multiple aspects (e.g. Contoso.Aspects.dll). In such cases it displays available aspects in the assembly and lets you select the one you want to use in your current CodeFluent Entities project.
Miscellaneous changes
Some other miscellaneous things were also added/fixed/enhanced such as the enhancing TFS integration or adding support for the CTRL+A keyboard shortcut in the method body editor was added.
We would love to hear your feedbacks, don’t hesitate to share your feedbacks on our forums or by commenting this post!
Enjoy,
Carl Anderson
CodeFluent Entities Aspects
CodeFluent Entities Aspects, formerly known as “Patterns”, allow developers to modify and extend the meta-model built by CodeFluent Entities before production. Aspects are platform independent, external to your model and therefore reusable in future developments. Moreover since aspects intervene upstream generation, they have an application-wide, cross-layer scope.
Let’s say a developer wants to add data localization capabilities to his application. CodeFluent Entities actually provides an internationalization aspect named SoftFluent.Localization. This aspect adds localization capabilities to your model by adding a new boolean property named “localizable” which can be set on properties.
Once the aspect was added to your project, you can declare a property localizable by selecting it and setting in the property grid the “Is Localizable” property to true.
For instance, we added a Description property to the Contact entity, defined as localizable. At generation, but before producers are actually run, the aspect will modify the in-memory representation of the model to add localization support. Technically speaking it will:
· add a ContactLocalized table with an Lcid column and the Description column,
· modify the stored procedures so the localized description column is retrieved as well,
· modify the C# methods to specify the Lcid as a parameter to those stored procedures.
Aspects being external to your model, once you created one, you can reuse it on other applications. Say your applications frequently need tracking capabilities of write operations. You could wrap those up in an aspect, so that you’re investing time to implement such feature once and for all.