4 min read

Getting ready

Download the latest release of the Common Service Locator from http://commonservicelocator.codeplex.com, and extract Microsoft.Practices.ServiceLocation.dll to your solution’s libs folder.

Complete the previous recipe, Setting up an NHibernate repository.

Following the Fast testing with SQLite in-memory database recipe in the previous article, create a new NHibernate test project named Eg.Core.Data.Impl.Test.

Include the Eg.Core.Data.Impl assembly as an additional mapping assembly in your test project’s App.Config with the following xml:

<mapping assembly=”Eg.Core.Data.Impl”/>


How to do it…

  1. In the Eg.Core.Data project, add a folder for the Queries namespace.
  2. Add the following IQuery interfaces:

    public interface IQuery
    {
    }
    public interface IQuery<TResult> : IQuery
    {
    TResult Execute();
    }

    
    
  3. Add the following IQueryFactory interface:

    {
    TQuery CreateQuery<TQuery>() where TQuery :IQuery;
    }

    
    
  4. Change the IRepository interface to implement the IQueryFactory interface, as shown in the following code:

    public interface IRepository<T>
    : IEnumerable<T>, IQueryFactory
    where T : Entity
    {
    void Add(T item);
    bool Contains(T item);
    int Count { get; }
    bool Remove(T item);
    }

    
    
  5. In the Eg.Core.Data.Impl project, change the NHibernateRepository constructor and add the _queryFactory field, as shown in the following code:

    private readonly IQueryFactory _queryFactory;

    public NHibernateRepository(ISessionFactory sessionFactory,
    IQueryFactory queryFactory)
    : base(sessionFactory)
    {
    _queryFactory = queryFactory;
    }

    
    
  6. Add the following method to NHibernateRepository:

    public TQuery CreateQuery<TQuery>() where TQuery : IQuery
    {
    return _queryFactory.CreateQuery<TQuery>();
    }

    
    
  7. In the Eg.Core.Data.Impl project, add a folder for the Queries namespace.
  8. To the Eg.Core.Data.Impl project, add a reference to Microsoft.Practices.ServiceLocation.dll.
  9. To the Queries namespace, add this QueryFactory class:

    public class QueryFactory : IQueryFactory
    {

    private readonly IServiceLocator _serviceLocator;

    public QueryFactory(IServiceLocator serviceLocator)
    {
    _serviceLocator = serviceLocator;
    }

    public TQuery CreateQuery<TQuery>() where TQuery : IQuery
    {
    return _serviceLocator.GetInstance<TQuery>();
    }
    }

    
    
  10. Add the following NHibernateQueryBase class:

    public abstract class NHibernateQueryBase<TResult>
    : NHibernateBase, IQuery<TResult>
    {
    protected NHibernateQueryBase(
    ISessionFactory sessionFactory)
    : base(sessionFactory) { }

    public abstract TResult Execute();
    }

    
    
  11. Add an empty INamedQuery interface, as shown in the following code:

    public interface INamedQuery
    {
    string QueryName { get; }
    }

    
    
  12. Add a NamedQueryBase class, as shown in the following code:

    public abstract class NamedQueryBase<TResult>
    : NHibernateQueryBase<TResult>, INamedQuery
    {

    protected NamedQueryBase(ISessionFactory sessionFactory)
    : base(sessionFactory) { }

    public override TResult Execute()
    {
    var nhQuery = GetNamedQuery();
    return Transact(() => Execute(nhQuery));
    }

    protected abstract TResult Execute(IQuery query);

    protected virtual IQuery GetNamedQuery()
    {
    var nhQuery = session.GetNamedQuery(
    ((INamedQuery) this).QueryName);
    SetParameters(nhQuery);
    return nhQuery;
    }

    protected abstract void SetParameters(IQuery nhQuery);

    public virtual string QueryName
    {
    get { return GetType().Name; }
    }
    }

    
    
  13. In Eg.Core.Data.Impl.Test, add a test fixture named QueryTests inherited from NHibernateFixture.
  14. Add the following test and three helper methods:

    [Test]

    public void NamedQueryCheck()
    {
    var errors = new StringBuilder();

    var queryObjectTypes = GetNamedQueryObjectTypes();
    var mappedQueries = GetNamedQueryNames();
    foreach (var queryType in queryObjectTypes)
    {
    var query = GetQuery(queryType);

    if (!mappedQueries.Contains(query.QueryName))
    {
    errors.AppendFormat(
    “Query object {0} references non-existent ” +
    “named query {1}.”,
    queryType, query.QueryName);
    errors.AppendLine();
    }
    }

    if (errors.Length != 0)
    Assert.Fail(errors.ToString());
    }

    private IEnumerable<Type> GetNamedQueryObjectTypes()
    {
    var namedQueryType = typeof(INamedQuery);
    var queryImplAssembly = typeof(BookWithISBN).Assembly;

    var types = from t in queryImplAssembly.GetTypes()
    where namedQueryType.IsAssignableFrom(t)
    && t.IsClass
    && !t.IsAbstract
    select t;
    return types;
    }

    private IEnumerable<string> GetNamedQueryNames()
    {
    var nhCfg = NHConfigurator.Configuration;

    var mappedQueries = nhCfg.NamedQueries.Keys
    .Union(nhCfg.NamedSQLQueries.Keys);
    return mappedQueries;
    }

    private INamedQuery GetQuery(Type queryType)
    {
    return (INamedQuery) Activator
    .CreateInstance(queryType,
    new object[] { SessionFactory });
    }

    
    
  15. For our example query, in the Queries namespace of Eg.Core.Data, add the following interface:

    public interface IBookWithISBN : IQuery<Book>
    {
    string ISBN { get; set; }
    }

    
    
  16. Add the implementation to the Queries namespace of Eg.Core.Data.Impl using the following code:

    public class BookWithISBN :
    NamedQueryBase<Book>, IBookWithISBN
    {
    public BookWithISBN(ISessionFactory sessionFactory)
    : base(sessionFactory) { }

    public string ISBN { get; set; }

    protected override void SetParameters(
    NHibernate.IQuery nhQuery)
    {
    nhQuery.SetParameter(“isbn”, ISBN);
    }

    protected override Book Execute(NHibernate.IQuery query)
    {
    return query.UniqueResult<Book>();
    }
    }

    
    
  17. Finally, add the embedded resource mapping, BookWithISBN.hbm.xml, to Eg.Core.Data.Impl with the following xml code:

    <?xml version=”1.0″ encoding=”utf-8″ ?>
    <hibernate-mapping >
    <query name=”BookWithISBN”>
    <![CDATA[
    from Book b where b.ISBN = :isbn
    ]]>
    </query>
    </hibernate-mapping>

LEAVE A REPLY

Please enter your comment!
Please enter your name here