ActiveRecord ICriterion Search Example (c#)

Filed in ActiveRecord | C# | NHibernate Leave a comment

In this post we are going to search using ICriterion to filter and sort the results. The only pre-requisite is that you properly configure your nHibernate environment, and like all my other code samples, know c#.

This one is pretty easy, first we are going to set the required references:

using NHibernate;
using NHibernate.Criterion;

Then we are going to define the ICriterion array. In this example, were are going to search for contacts that:

  • Belonging to the logged on owner (OwnerID variable).
  • LastName starts with some string entered by the user (LastNameValue variable)
  • Were added after a specific date chosen by the user (StartDate variable)

For the LastName like search, nHibernate gives us some options in the MatchMode enum: Anywhere, End, Exact, Start. In the snippet below, you will notice I went with Start.

Finally, we are going to sort the results by LastName, then FirstName.

ICriterion[] query = {
Expression.Eq("OwnerID", OwnerID),
Expression.Like("LastName",LastNameValue,MatchMode.Start),
Expression.Ge("CreationDate",StartDate) };

Order[] order = {
Order.Asc("LastName"),
Order.Asc("FirstName")};

Contact[] results = contact.FindAll(order, query);

That’s it!

Related articles:

,

Codesmith Templates for nHibernate and ASP.NET MVC

Filed in ActiveRecord | Codesmith 1 Comment

Reason #52356 I love using Castle’s ActiveRecord is that CRUD is automatically handled for you, which is a major time saver. I’m always looking for any edge to speed up the development process or automate redundant tasks, and that little drive led me to Codesmith Tools. What’s so cool about Codesmith? The fact that once you define a table — and all major databases are supported — clicking a single button can generate your class file, controller methods, stored procedures, or views.

I started using Codesmith with ASP.NET web forms, and when I first migrated to ASP.NET MVC, was unclear how/where to incorporate Codesmith into this new MVC environment. Well it was easier than I thought! Below I’m going to break down the Codesmith template file (.cst) I use to generate my ActiveRecord classes, which is done in c#:

Codesmith template references

The following section appears at the top of the template:

<%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Generates a very simple business object." %>
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context" Description="Table that the object is based on." %>
<%@ Property Name="Namespace" Type="System.String" Default="" Optional="False" Category="MethodInfo" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Assembly Name="System.Data" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Import Namespace="System.Data" %>

The most important rows to notice are the second and third. The SourceTable property tells Codesmith that you are going to choose a table which the rest of the code will reference. The Namespace property, which is tagged as optional, is simply a property I made up. In the code below, you will see how it is used. It is just a placeholder for the template, and you can have as many as you want.

Codesmith template

The next section is the template itself. It will look just like Classic ASP or MVC. In a nutshell, it is a block of text, with Codesmith markup appearing in between <% %> tags.

First we add the using namespaces our c# repository file will need to reference:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate;
using NHibernate.Criterion;
using Castle.ActiveRecord;

Since this is an ActiveRecord class, and we use ICriterion for our queries, we include the NHibernate and ActiveRecord references. Next up is our namespace wrapper. You’ll notice the markup that references the Namespace property at the top of the page:

namespace <%= Namespace %>
{

Whatever you type into the textbox will pop in between the tags. Next up is the real meat: the class definition. You’ll notice all the ActiveRecord attributes above each property, as well as some methods, and finally the closing } for the namespace:

[ActiveRecord("<%= GetClassName(SourceTable) %>")]
public class <%= GetClassName(SourceTable) %> : ActiveRecordBase<<%= GetClassName(SourceTable) %>>
{
public <%= GetClassName(SourceTable) %>()
{
}

#region Properties
<% for (int i = 0; i < SourceTable.PrimaryKey.MemberColumns.Count; i++) { %>

[PrimaryKey(PrimaryKeyType.Native, "<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>")]
public <%= GetCSharpVariableType(SourceTable.PrimaryKey.MemberColumns[i]) %> <%= SourceTable.PrimaryKey.MemberColumns[i].Name %> { get; set; }

<% } %>
<% for (int i = 0; i < SourceTable.NonPrimaryKeyColumns.Count; i++) { %>
[Property]
public <%= GetCSharpVariableType(SourceTable.NonPrimaryKeyColumns[i]) %> <%= GetPropertyName(SourceTable.NonPrimaryKeyColumns[i]) %> { get; set; }

<% if (i < SourceTable.NonPrimaryKeyColumns.Count - 1) Response.Write("\r\n"); %>
<% } %>
#endregion

#region Methods
public static void DeleteAll()
{
DeleteAll( typeof(<%= GetClassName(SourceTable) %>) );
}

public static <%= GetClassName(SourceTable) %>[] Find(ICriterion[] query, Order[] order)
{
return <%= GetClassName(SourceTable) %>.FindAll(order, query);
}
#endregion
}
}

The final section is a series of functions used by the template which extracts class names, database column types from the table, etc.:

<script runat="template">

public string GetPropertyName(ColumnSchema column)
{
string propertyName = column.Name;

if (propertyName == column.Table.Name + "Name") return "Name";
if (propertyName == column.Table.Name + "Description") return "Description";

if (propertyName.EndsWith("TypeCode")) propertyName = propertyName.Substring(0, propertyName.Length - 4);

return propertyName;
}

public string GetCSharpVariableType(ColumnSchema column)
{
if (column.Name.EndsWith("TypeCode")) return column.Name;

switch (column.DataType)
{
case DbType.AnsiString: return "string";
case DbType.AnsiStringFixedLength: return "string";
case DbType.Binary: return "byte[]";
case DbType.Boolean: return "bool";
case DbType.Byte: return "byte";
case DbType.Currency: return "decimal";
case DbType.Date: return "DateTime";
case DbType.DateTime: return "DateTime";
case DbType.Decimal: return "decimal";
case DbType.Double: return "double";
case DbType.Guid: return "Guid";
case DbType.Int16: return "short";
case DbType.Int32: return "int";
case DbType.Int64: return "long";
case DbType.Object: return "object";
case DbType.SByte: return "sbyte";
case DbType.Single: return "float";
case DbType.String: return "string";
case DbType.StringFixedLength: return "string";
case DbType.Time: return "TimeSpan";
case DbType.UInt16: return "ushort";
case DbType.UInt32: return "int";
case DbType.UInt64: return "ulong";
case DbType.VarNumeric: return "decimal";
default:
{
return "__UNKNOWN__" + column.NativeType;
}
}
}

public string GetClassName(TableSchema table)
{
if (table.Name.EndsWith("s"))
{
return table.Name.Substring(0, table.Name.Length - 1);
}
else
{
return table.Name;
}
}
</script>

When executed, the above code creates your class file, ready for copying and pasting into your project, and fully crud-enabled. A brilliant little feature Codesmith includes is a running counter of how many lines of code it has generated for you, along with the ability to set your hourly rate and however many lines of code you can manually generate per hour, so you can see your ROI.

, , , , ,

Initialize global asax in MVC for NHibernate ActiveRecord

Filed in ActiveRecord | ASP.NET MVC 1 Comment

Initializing your global.asax for MVC and NHibernate’s ActiveRecord is really easy. There are really only two sections you need to touch: the using section and Application_Start().

Configure using section

Out of the box, you don’t have to do anything if you are NOT using ActiveRecord for CRUD. If you want to use ActiveRecord, here are the using statements you need to add:

using System.Reflection;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;

Those namespaces are used in the next section, which is

Application_Start()

There are only three lines of code to initialize ActiveRecord to specify the settings are sitting in web.config:

IConfigurationSource source = System.Configuration.ConfigurationManager.GetSection("activeRecord") as Castle.ActiveRecord.Framework.IConfigurationSource;
Assembly asm1 = typeof(Certification).Assembly;
ActiveRecordStarter.Initialize(new Assembly[] { asm1 }, source);

Those lines should appear BELOW the RegisterRoutes() call. If you don’t include the above lines, you will receive the following nastygram:

An ActiveRecord class (Contact) was used but the framework seems not properly initialized. Did you forget about ActiveRecordStarter.Initialize() ?


, ,

How to execute a Query in c# using nHibernate, ICriterion, HQL

Filed in ActiveRecord | C# | NHibernate Leave a comment

Below are two samples on how to create a query with ActiveRecord and ICriterion.

Example 1: Select all contacts from Texas

public static Contact[] FindByState(string State)
{
ICriterion[] query = { Expression.Eq("State", State) };
Order[] sort = { Order.Asc("LastName") }

return Contact.FindAll(sort, query);
}

The Controller’s syntax would be this:

Contact[] contacts = Contact.FindByState("TX");

Example 2: SQL style query

ArrayList stateslist = new ArrayList();
stateslist.Add("TX");
stateslist.Add("VA");

The next part is where all the magic happens. The “SELECT” part is done for us automatically, so we simply add our WHERE clause. In the example you’ll notice the parameter format (:variablename). The in parameter is wrapped with parentheses:

string hql = String.Format("FROM Contact c where State in (:states)");
SimpleQuery&lt;Contact&gt; q = new SimpleQuery<Contact>(hql);
q.SetParameterList("states", stateslist);
q.SetQueryRange(25);
Contact[] result = q.Execute();

If we wanted to execute a LIKE search:

string hql = String.Format("FROM Contact c LastName like :lastname");
...
q.SetParameter("lastname", stringvalue + "%");
...

Here is some further reading on HQL:

  • http://www.castleproject.org/ActiveRecord/documentation/v1rc1/usersguide/hql.html
  • https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html_single/#d0e8963

, , , ,

How To Create a Class with ActiveRecord

Filed in ActiveRecord | C# | NHibernate Leave a comment

So in this installment, we’re going to look at what goes into creating a class using ActiveRecord. One of the cool parts of ActiveRecord is the fact that you don’t have to waste time with CRUD statements because they are baked in for you! So here is the anatomy of a class:

1. The using statements:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate;
using NHibernate.Criterion;
using Castle.ActiveRecord;

I created some CodeSmith templates which I use to generate all my classes, the above using statements are my defaults. Next is the class name, the required attributes, and the properties:

[ActiveRecord("<em>TABLE NAME</em>")]
public class Contact : ActiveRecordBase&lt;Contact&gt;
{
public Contact()
{
}

[PrimaryKey(PrimaryKeyType.Native, "ID")]
public int ID { get; set; }

[Property]
public string FirstName { get; set; }

[Property]
public string LastName { get; set; }

[Property]
public string State { get; set; }

[Property]
public DateTime CreationDate { get; set; }

[Property(Column="CreatedByUser"]
public int OwnerUserID { get; set; }

The [Property] attribute indicates that field exists in the table. If you don’t include [Property] then that field will not be included in CRUD statements. Also, if you want the property name to be different from the database column name, simply set Column=ColumnName like the “CreatedByUser” sample above.

, ,

Using nHibernate, Castle ActiveRecord, and ASP.NET MVC Together

Filed in ActiveRecord | ASP.NET MVC | C# | Environment Setup | NHibernate 3 Comments

So this is my first post, with that this blog’s objective: to post all the code shortcuts, how-to’s, tips-tricks, etc. so they are handy whenever I need them. It always seems that at some point I need to do something that I did 5 projects ago, and forgot to save that snippet and can’t quite find it!

For this entry, we’re going to configure a new web application in the following sequence:

1. Create ASP.NET MVC 1.0 project in Visual Studio 2008

2. Copy and reference the required nHibernate dlls

3. Configure web.config

4. Initialize global.asax

Pre-requisites: If you haven’t already installed MVC, go here: http://www.asp.net/mvc/download/.

Create ASP.NET MVC 1.0 project in Visual Studio 2008

1. Open Visual Studio 2008

2. Click “File” –> “New Project” and select “ASP.NET MVC Web Application” under the c# menu

Select your location, project name, etc.

Copy and reference the required nHibernate files and dlls

1. Download the latest ActiveRecord release here: http://bit.ly/8HdvIU

For detailed documentation on ActiveRecord, visit the Castle Project site here: http://bit.ly/8pzxyb and here: http://bit.ly/8jzycs.

2. Unzip, copy and then reference the following assemblies into your bin folder:

  • Castle.ActiveRecord.dll
  • Castle.Core.dll
  • Castle.Components.Validator.dll
  • Castle.DynamicProxy.dll
  • NHibernate.dll
  • Iesi.Collections.dll
  • log4net.dll

Configure web .config

1. Add the following elements to configSections:

<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
<section name="activeRecord" type="Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord"/>

2. Add the following elements right after /configSections:

SQLServer 2005/2008

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.connection_string">Server=localhost;initial catalog=<em>YOURDB</em>;uid=<em>YOURUSERNAME</em>;pwd=<em>YOURPASSWORD</em></property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
<mapping assembly="<em>YOURASSEMBLY</em>"/>
</session-factory>
</hibernate-configuration>

<activeRecord isWeb="true">
<config>
<add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2005Dialect"/>
<add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider"/>
<add key="hibernate.connection.connection_string" value="Server=localhost;initial catalog=<em>YOURDB</em>;uid=<em>YOURUSERNAME</em>;pwd=<em>YOURPASSWORD</em>"/>
</config>
</activeRecord>

MySQL

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MySQLDialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
<property name="connection.connection_string">Database=<em>YOURDB</em>;Server=localhost;User Id=<em>YOURUSERNAME</em>;Password=<em>YOURPASSWORD</em></property>
<property name="show_sql">true</property>
<property name="hbm2ddl.keywords">none</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
<mapping assembly="<em>YOURASSEMBLY</em>" />
</session-factory>
</hibernate-configuration>

<activeRecord isWeb="true">
<config>
<add key="hibernate.connection.driver class" value="NHibernate.Driver.MySqlDataDriver" />
<add key="hibernate.dialect" value="NHibernate.Dialect.MySQLDialect" />
<add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
<add key="hibernate.connection.connection_string" value="Database=<em>YOURDB</em>;Server=localhost;User Id=<em>YOURUSERNAME</em>;Password=<em>YOURPASSWORD</em>" />
</config>
</activeRecord>

For logging, you need to add the following elements, regardless of database type:

<log4net>
<appender name="NHibernateFileLog" type="log4net.Appender.RollingFileAppender">
<file value="Logs/nhibernate.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="100KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%t] %-5p %c - %m%n" />
</layout>
</appender>
<appender name="GeneralLog" type="log4net.Appender.RollingFileAppender">
<file value="Logs/general.txt" />
<appendToFile value="true" />
<maximumFileSize value="100KB" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%t] %-5p %c - %m%n" />
</layout>
</appender>
<appender name="DataLog" type="log4net.Appender.RollingFileAppender">
<file value="Logs/data.txt" />
<appendToFile value="true" />
<maximumFileSize value="100KB" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%t] %-5p %c - %m%n" />
</layout>
</appender>
<!-- levels: DEBUG, INFO, WARN, ERROR, FATAL -->
<root>
<level value="DEBUG" />
<appender-ref ref="GeneralLog" />
</root>
<logger name="NHibernate" additivity="false">
<level value="DEBUG" />
<appender-ref ref="NHibernateFileLog" />
</logger>
<logger name="Pushable.Data" additivity="false">
<level value="DEBUG" />
<appender-ref ref="DataLog" />
</logger>
</log4net>

Initialize Global.asax

1. Open global.asax in code view

2. Add the following using statements:

using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;

3. Update Application_Start so it looks like this:

protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);

IConfigurationSource source = System.Configuration.ConfigurationManager.GetSection("activeRecord") as Castle.ActiveRecord.Framework.IConfigurationSource;
Assembly asm1 = typeof(<em>ONE OF YOUR ASSEMBLIES, I.E. CONTACT</em>).Assembly;

ActiveRecordStarter.Initialize(new Assembly[] { asm1 }, source);
}

That’s it! So what we’ve done here is configure our environment, in upcoming posts, we’ll dig into actual code and do some fun things with jQuery. Also, I’ll be revisiting this post with some screenshots in the near future. Finally, if you know of better/more efficient ways to do some of these same tasks, I’m all ears!

, , ,

TOP