views:

228

answers:

1

If I needed to get NHibernate to support more databases (not included in the list of supported: https://www.hibernate.org/361.html), assuming that database can be accessed using it's built-in query language,but not SQL (example: http://kx.com/Products/kdb+.php)...

  • How will I be able to get NHibernate to work with these databases?
+3  A: 

NHibernate is designed to operate with dialects of SQL and not ad hoc query languages. This will be very tricky to accomplish. But to answer your question, you need:

  1. An ADO.NET provider for your database (this would be a separate question).
  2. A Driver class (derived from NHibernate's DriverBase). Here is one I have written in the past (somewhat anonymised):

    public sealed class XxxClientDriver : DriverBase
    {
        public override IDbConnection CreateConnection()
        {
            return XxxClientFactory.Instance.CreateConnection();
        }
        public override IDbCommand CreateCommand()
        {
            return XxxClientFactory.Instance.CreateCommand();
        }
        public override bool UseNamedPrefixInSql
        {
            get { return true; }
        }
        public override bool UseNamedPrefixInParameter
        {
            get { return true; }
        }
        public override string NamedPrefix
        {
            get { return "@"; }
        }
    }
    
  3. Possibly (definitely in your case) a Dialect, deriving from NHibernate's Dialect class, that defines classes to render each particular syntax element in your language (note, though, that this is still SQL-orientated, which is I suspect where you are going to fall down here). An example in my case:

    public sealed class XxxDialect : Dialect
    {
        public override JoinFragment CreateOuterJoinFragment()
        {
            return new XxxJoinFragment();
        }
    }
    
  4. As many non-standard syntax elements (compared to normal SQL) as your language has. Again, an example from my case:

    public sealed class XxxJoinFragment : JoinFragment
    {
        private readonly SqlStringBuilder _afterFrom;
        public XxxJoinFragment()
        {
            _afterFrom = new SqlStringBuilder();
        }
        private SqlStringBuilder AfterFrom
        {
            get { return _afterFrom; }
        }
        public override SqlString ToFromFragmentString
        {
            get { return _afterFrom.ToSqlString(); }
        }
        public override SqlString ToWhereFragmentString
        {
            get { return SqlString.Empty; }
        }
        public override void AddJoin(string tableName, string alias,
            string[] fkColumns, string[] pkColumns,
            JoinType joinType)
        {
            AddCrossJoin(tableName, alias);
        }
        public override void AddJoin(string tableName, string alias,
            string[] fkColumns, string[] pkColumns,
            JoinType joinType, string on)
        {
            AddJoin(tableName, alias, fkColumns, pkColumns, joinType);
        }
        public override void AddCrossJoin(string tableName, string alias)
        {
            AfterFrom.Add(", ").Add(tableName).Add(" ").Add(alias);
        }
        public override void AddJoins(SqlString fromFragment, SqlString whereFragment)
        {
            AddFromFragmentString(fromFragment);
        }
        public override bool AddCondition(string condition)
        {
            return true;
        }
        public override bool AddCondition(SqlString condition)
        {
            return true;
        }
        public override void AddFromFragmentString(SqlString fromFragmentString)
        {
            AfterFrom.Add(fromFragmentString);
        }
    }
    

As you can see, in my case (a SQL-based query language with implicit join conditions) this was not too hard. But in your case I suspect you're going to be up against it. Good luck!

David M