Archive for the 'SQL' Category

NHibernate Caching Explained, finally!

Gabriel Schenker has just posted an excellent article explaining in detail how to the 1st and 2nd level cache in NHibernate works. This is a long overdue article on caching that will greatly benefit the community. The article also explains the differences between Get(id) and Load(id) when retrieving entities through NHibernate. I am recommending this article because it is an in depth look at one of the pieces I covered earlier on Ayende’s session from KaizenConf.

KaizenConf Workshops – Advanced NHibernate

As some of you know I am attending KaizenConf for the next few days. I am going to use my blog as my notepad as I take notes during different workshops and sessions. My note taking skills sometimes have a lot to be desired so be patient if these notes look very sketchy. I will try my best to come back through and make sense of them later.

Advanced NHibernate

I am currently sitting through Ayende’s workshop on Advanced NHibernate and there is some really good stuff going on here. Three of the topics I have found most interesting is Multi-Tenancy, Full text indexing with NHibernate Search, and caching with NHibernate. NHibernate search is a project that combines Lucene, a proven java index tool, and NHibernate to alleviate strain on the database engine by keeping indexes on disk and performing queries on that data faster. Indexing is accomplished by decorating entities with attributes. Of all these topics caching with NHibernate has really grabbed my attention as it probably has the greatest results for the applications I am currently working.

Caching with NHibernate

1st Level cache –Contains Identity Map – Session – Single instance of an object in a particular session

2nd Level Cache – contains the SessionFactory – lives for the entire application lifetime, it also has 4 levels of cache within it:

timestamp
query cache
collection cache
entity cache

 

Caching Configuration

Enable query cache <property name=”cache.use_second_level_cache”>True</property> in NHConfig – A single on off switch in the application to enable/disable caching is not a good solution because caching is complex and could affect business rules and performance. So you have to enable caching for a specific entity by using Cache_usage = CacheMode (ReadWrite for Ayende’s samples) in the entity mapping file. The NHibernate cache hashtables are stored like below:

Entities Cache:
————————-
Blog#1 : { Name: “…”}
Post#1 : {…}
Post#2 {…}

Collection Cache
—————————
Blog#1.Posts { 1,2,3,4,5,6} – stores id’s only

Query Cache:
—————————
“select top 5 * from Post” : {1,2,3,4} // stores id’s only

Ayende used his blog sample for all of the code examples today. When he put caching on the Blog, and the collection of posts in the blog map and on the post entity the fewest calls to the database occurred. To enable query caching the property cache.use_query_cache = true in the config file.

Session.Load vs Session.Get

Load == I know the entity exists in the database, it returns a proxy to the object. Throws an exception if the object is not lazy loaded and cannot be found.

Get == NH really goes to the database and fetches a row or throws an exception if it does not exist.

Which one of these to use depends on the business rule for the entity.

 

NHibernate Contrib project descriptions

NHibernate cache libraries:

PrevelanceCache – persistent caching for smart client applications

SysCache – using ASP.net caching – gives it the ability to put things in the cache and forget about it – only works if you have one machine.  Other wise you get cache poisoning.

SysCache2 – ASP.net caching in the farm – maybe application is not the only thing that updates the database. This is good when the application is not the sole owner of the database.

MemCache – a distributed hashtable, thats it basically it is distributed caching.– Server sitting on TCP with a hashtable – the Client caches the key and always goes back to same server in farm for cache retrieval. Very simple, works very well. This is also known as MemCacheD and is the same caching strategy that Facebook uses.

SharedCache – SharedCache from CodePlex

Velocity – From Microsoft – more complex than memcache, more options but they validate the cache space you have.

 

Other NHibernate Contrib Projects

NHibernate.Linq – pretty good, handles most of the common scenarios, does not handle the crazy scenarios that are capable in LINQ. Currently working on a fully functional LINQ library.

NHibernate.Validator– Just as you can specify constraints in SQL Server. You can specify constraints in your mapping file and the validator will validate that for you.

Spatial – GIS applications

Shards – partition the data across multiple db’s – written by Google to deal with problem of having multiple database. You can teach NHibernate a sharding strategy so that it knows which database to use. This is a strategy that is used by companies such as Facebook.

 

Another very interesting topic Ayende talked about is self optimizing queries. This would be used by session.Future<TYPE>() you could use this in your repositories on all lists/CreateCriteria methods. This creates a MultiCriteria which returns multiple result sets in one database trip. This is very similar/exactly like multiple result sets in stored procedures.

IRepository Code

This is by request from Frank Mao, he was wanting me to post up the code I am using for IRepository<T> so here it is:


public interface IRepository<T>
{
//IList<T> FetchList();
ICriteria CreateCriteria();
T Get(object id);
void Load(T obj, object id);
void Delete(T entity);

void DeleteAll();
void DeleteAll(DetachedCriteria where);
T Save(T entity);
T SaveOrUpdate(T entity);
T SaveOrUpdateCopy(T entity);
void Update(T entity);
long Count(DetachedCriteria criteria);
long Count();
bool Exists(DetachedCriteria criteria);
bool Exists();
IList<T> FindAll(DetachedCriteria criteria, params Order[] orders);
IList<T> FindAll(Order order, params ICriterion[] criteria);
IList<T> FindAll(Order[] orders, params ICriterion[] criteria);
T FindFirst(params Order[] orders);
T FindFirst(DetachedCriteria criteria, params Order[] orders);
T FindOne(params ICriterion[] criteria);
T FindOne(DetachedCriteria criteria);

ProjT ReportOne<ProjT>(ProjectionList projectionList);
ProjT ReportOne<ProjT>(DetachedCriteria criteria, ProjectionList projectionList);
IList<ProjT> ReportAll<ProjT>(ProjectionList projectionList);
IList<ProjT> ReportAll<ProjT>(bool distinctResults, ProjectionList projectionList);
IList<ProjT> ReportAll<ProjT>(ProjectionList projectionList, params Order[] orders);
IList<ProjT> ReportAll<ProjT>(bool distinctResults, ProjectionList projectionList, params Order[] orders);
IList<ProjT> ReportAll<ProjT>(DetachedCriteria criteria, ProjectionList projectionList, params Order[] orders);
IList<ProjT> ReportAll<ProjT>(bool distinctResults, DetachedCriteria criteria, ProjectionList projectionList, params Order[] orders);
}
}

I should note that this is a slightly modified version of IRepository that I got from the UnitOfWork tutorial code that is posted here: http://hibernatingrhinos.googlecode.com/svn/trunk/UnitOfWork/src/NHibernateRepository/

SQL Server Timestamp field and Fluent-NHibernate

This morning I was trying to do a Version mapping with Fluent-NHibernate on a timestamp column in a SQL database, this didn’t work so good right out of the box so I dug around and found some information here and there and once I pieced it together it all worked.

First off the mapping:


public class ProjectMap : ClassMap<Project>, IMapGenerator
{
        public ProjectMap()
        {
            WithTable("Projects");

            Id(x => x.Id)
                .GeneratedBy
                .GuidComb()
                .WithUnsavedValue("00000000-0000-0000-0000-000000000000");

            Map(x => x.Name)
                .WithLengthOf(50)
                .CanNotBeNull();

            Map(x => x.Started);
            Map(x => x.Ended);
            Map(x => x.Description);

            Version(x => x.TimeStamp)
                .TheColumnNameIs("LastChanged");
          }

}

public override VersionPart Version(System.Linq.Expressions.Expression<Func<ProjectResource, object>> expression)
{
     var versionPart = new VersionPart(ReflectionHelper.GetProperty(expression));

     versionPart.SetAttribute("type", "ProjectTracker.Library.Mapping.UserTypeTimestamp, ProjectTracker.Library");
     versionPart.SetAttribute("generated", "always");
     versionPart.SetAttribute("unsaved-value", "null");

     AddPart(versionPart);
     return versionPart;
}
 

The main thing here is the overridden Version method. What this override is doing is setting up a few attributes required to make this all work properly, I think most of them are self explanetory. Inside this method is a set attribute method that sets the type of the timestamp to UserTypeTimestamp. The coded for this class follows below:

UserTypeTimestamp Class:


public class UserTypeTimestamp : IUserVersionType
    {
        #region IUserVersionType Members

        public object Next(object current, ISessionImplementor session)
        {
            return current;
        }

        public object Seed(ISessionImplementor session)
        {
            return new byte[8];
        }

        public object Assemble(object cached, object owner)
        {
            return DeepCopy(cached);
        }

        public object DeepCopy(object value)
        {
            return value;
        }

        public object Disassemble(object value)
        {
            return DeepCopy(value);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        public bool IsMutable
        {
            get { return false; }
        }

        public object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            return rs.GetValue(rs.GetOrdinal(names[0]));
        }

        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            NHibernateUtil.Binary.NullSafeSet(cmd, value, index);
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public System.Type ReturnedType
        {
            get { return typeof(byte[]); }
        }

        public SqlType[] SqlTypes
        {
            get { return new SqlType[] { new SqlType(DbType.Binary) }; }
        }

        public int Compare(object x, object y)
        {
            byte[] xbytes = (byte[])x;
            byte[] ybytes = (byte[])y;
            if (xbytes.Length < ybytes.Length)
            {
                return -1;
            }
            if (xbytes.Length > ybytes.Length)
            {
                return 1;
            }
            for (int i = 0; i < xbytes.Length; i++)
            {
                if (xbytes[i] < ybytes[i])
                {
                    return -1;
                }
                if (xbytes[i] > ybytes[i])
                {
                    return 1;
                }
            }
            return 0;
        }

        bool IUserType.Equals(object x, object y)
        {
            return (x == y);
        }

        #endregion
    }

Now for the Business object change this:

private byte[] timeStamp = new byte[];

To this:


private byte[] timeStamp;
internal byte[] TimeStamp
{
     get { return timeStamp; }
     set { timeStamp = value;}
}

With the addition of the class and an internal Property so NHibernate can access the data in the timestamp everything works pefectly to implement optimistic concurrency with Fluent-NHibernate and SQL Server timestamp fields.

CONNX Data Access Software

Tonight I am going to write a short review on a nice little product that we use company wide on a daily basis. The product I am speaking of is called CONNX. So you are now wondering what is CONNX? CONNX provides connection to data sources and legacy applications through open standards across all major platforms. We use CONNX extensively to get data in and out of an RMS database on a VMS server into SQL Server 2005. I will not go into detail on this process to much during this post, I am saving this for later. CONNX can take data out of relational and non relations database systems, transaction systems and legacy applications. Some examples of the compatible systems are ADABAS, DB2, IMS, VSAM-MVS, Informix, Oracle, SYBASE, RMS, PostgreSQL, and SQL Server.

 Installation of CONNX is fairly straighforward and the wizard walks you through most everything. Starting with CONNX 1o, you will need to also have a server or box on the network that can act as the CONNX license server. CONNX also installs a nice little configuration management tool in Windows and comes with a powerful query application called InfoNaut.

I have only had a few issues with putting data back into RMS through CONNX, most of this has been configuration issues on my SQL Server box that seem to be resolved now. There are multiple licensing schemes available through CONNX to fit almost any need. So if you get into a project where you need data in and out of systems that you are not familiar with, look at CONNX and maybe you’ll be surprised.

SQL Server 2005 Dynamic Crosstab Query

A few weeks ago we started working on a statistical analysis piece of our produciton managment application. If you don’t know, I am the Information Services Director for a small manufacturing company, but I will write more on that later.

We recently started accumulating quality assurance information digitally inside our software, which begs the age old question: “What good is data if you can’t get to it?”. Enter statistical analysis, what we want to do is be able to take all of the possible issues that can happen and cross reference it against one or more manufacturing jobs. So this would be a piece of cake in excel, but wait we are not using excel for this and discourage our users from doing so.

Read more »