Monday, January 04, 2010
Thursday, April 10, 2008
NHibernate Tales n°1 - Mapping Oracle RAW [Guid]
Hi, recently I read many requests about how to map an Oracle RAW() Type. About 2 months ago, I was one of the those who was asking for a solution, I really cannot believe how could be possible there is not a solution, so searching in the Net I found 3 kind of solution, then, I decided what was the better for me and so I've implemented in my project, let's begin.
First of all, in general a RAW column data type describe a raw binary data, generally describing a Guid. Even generally, when using a RAW data type mean, as .NET world, using a GUID, so our need is to use a RAW as GUID.
Normally there are 2 modes of reading a RAW data type, in the ADO.NET way, from a command:
- if not is specified the RAW column returns as a Byte[] array
- if specified, it's possible to use during reading the RAWTOHEX(columnName) that converts from a raw byte array to a binary string, and vice versa during writing the HEXTORAW(columnName) that converts back from a binary string to a raw byte array.
but what if we want to map that column data type in a HBM mapping? Well, there are 3 ways (usually I use the last one):
- Creating a custom NHibernate Dialect inheriting from the OracleDialect and map the Guid data type so the convertion is made while reading clearly by the engine
- Specify a "formula" surrounding the column name and decorate the column name with the RAWTOHEX function, bu the problem came up when we want to write and we should use the HEXTORAW function
- Creating a custom IUserType that converts to and from the RAW type.
As I said before I prefer the last one, so here is my solution: (here i will discuss the code in pieces, then in the end of the post is available the code to download)
Firts of all, we start creating a class named (in my case) RawType:
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using NHibernate;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;
namespace MySolution.Data.Types
{
public class RawType : IUserType
{
The class must inherits from IUserType, this interface instructs NHibernate we want map a specifed database column name with a custom type. Next, to correctly implement the type we need to specify the NHibernate SqlType represented by our custom type, I used the DbType.Binary in a static SqlType array variable as:
private staticSqlType[] types = newSqlType[] { newSqlType(DbType.Binary) };
Next the core part of the implementation are the methods NullSafeGet and NullSafeSet that are used to handle the "raw ado read value" and translate it depending if we are reading or writing. In order, the implementation handles this situation as follow:
Reading - the value is converted from the raw binary data to System.String, this is done using the System.Guid structure that permit to create a Guid from binary array assuming a valid 32 byte array, the the ToString method with the "N" format creates a guid strings without wpecial characters
Writing - the value is converted from System.String to a raw binary representation, this is yet done using the System.Guid structure ToByteArray method
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
string result = null;
byte[] buffer = (byte[])NHibernateUtil.Binary.NullSafeGet(rs, names[0]);
if (null != buffer)
{
result = new Guid(buffer).ToString("N");
Array.Clear(buffer, 0, buffer.Length);
}
return result;
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
if (null != value)
{
byte[] buffer = new Guid(((string)value)).ToByteArray(); NHibernateUtil.Binary.NullSafeSet(cmd, buffer, index);
Array.Clear(buffer, 0, buffer.Length);
}
}
The rest part of the class is a normal implementation of a NHibernate custom type.
Now the interesting part is the hbm mapping file. We can use our type in any property even as id, declaring the generator as "assigned" because we can't use any algorithm to assign the id value.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="MySolution"
namespace="MySolution.Common.Entities">
<class name="Class1"
table="TABLE1">
<id name="Id"
type="MySolution.Data.Types.RawType, MySolution.Data">
<column name="ID" />
<generator class="assigned" />
</id>
The last thing, I implemented an helper static method which generates a new "guid" from scratch.
public static string GenerateNewId()
{
Guid nextVal = Guid.NewGuid();
return nextVal.ToString("N");
}
I hope this helps, I spend much time in finding a solution to my problem, because in the net there's no so much on the argument, so I had to "create" a solution for my project. The next post would be another kind of serializing/deserializing binary raw to and from an Oracle Database taking care when the RAW column is not sure that contains a "well formed" binary data to build a System.Guid.
Here is the complete RawType code:
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using NHibernate;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;
namespace MySolution.Data.Types
{
public class RawType : IUserType
{
public static string GenerateNewId()
{
Guid nextVal = Guid.NewGuid();
return nextVal.ToString("N");
}
private static SqlType[] types = new SqlType[] { new SqlType(DbType.Binary) };
public object Assemble(object cached, object owner)
{
return DeepCopy(cached);
}
public new bool Equals(object x, object y)
{
return (x == null ? false : x.Equals(y));
}
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 true; }
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
string result = null;
byte[] buffer = (byte[])NHibernateUtil.Binary.NullSafeGet(rs, names[0]);
if (null != buffer)
{
result = new Guid(buffer).ToString("N");
Array.Clear(buffer, 0, buffer.Length);
}
return result;
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
if (null != value)
{
byte[] buffer = new Guid(((string)value)).ToByteArray();
NHibernateUtil.Binary.NullSafeSet(cmd, buffer, index);
Array.Clear(buffer, 0, buffer.Length);
}
}
public object Replace(object original, object target, object owner)
{
return original;
}
public Type ReturnedType
{
get { return typeof(string); }
}
public SqlType[] SqlTypes
{
get { return types; }
}
}
}
Ciao!
Saturday, March 29, 2008
Beginning NHibernate Story
Hi, I want, with this post, start writing about NHibernate and the related world of development. I recently started developing and using NHibernate in some projects, and I found the first set of great functionalities offered by the framework, I said the first set because I know that we know just a little subset of all the functionalities of the framework, specially all of us coming from the .NET area of development.
I've got the opportunity to use the framework in a project recently, I also used before but with a small set of features, and I've done some usage of the tool against the Oracle 10g Database, with ome restrictions, but we, the team, found some interesting patterns and practice to use with.
I'll like to share with all of you about our experience, because we came up from the community, and we want to give tro the community our contribution, so I decided to begin to write in my blog about NHibernate, our experience, usage stories and code to share. I know Ayende owns the better blog about NHibernate, but I wish to contribute.
So, I know and I believe that NHibernate it's still one of the better frameworks, I wish to came up with some initial posts about:
- Oracle RAW (GUID) type handler (implemented with a custom NH type)
- NHibernate criteria helper objects, which helps in the day by day ICriteria queries
So in the next days I'll begin to write about. Ciao!
Tuesday, November 27, 2007
Development Tools, libraries and more n°1
Wednesday, October 17, 2007
Helpful tools n°3
It seems to be an ineteresting tool, even if few diagrams are implemented, but I wish to take a try and then write something more about.
The product download can be found at: http://www.tangiblearchitect.net/modellingtools.html
Ciao
Friday, July 13, 2007
Helpful tools n°2
Yesterday night I was looking for some news from an open source project, accidentally I found 2 interesting tools, one from Microsoft and one from Businessware Architects.
The one from Microsoft is the XSDObjectGen, a tool for gerating code, pure classes, from xsd Schemas. It's free to download at: http://www.microsoft.com/downloads/details.aspx?familyid=89e6b1e5-f66c-4a4d-933b-46222bb01eb0&displaylang=en
The one from Businessware Architects is the CodeXS, a code generation tool who does the same as XSDObjectGen and XSD tools from Microsoft. The Only difference is that CodeXS is open source and more, efficient, modular... It's frre to download (registration required) at: http://www.bware.biz/default.htm?http://www.bware.biz/DotNet/Development/CodeXS/Article/Article_web.htm. There's also an interesting article related to the tool which take a tour over functionality and more.
So I wish to take a try to evaluate the potential from that tool. Maybe one could say I found nothing new to the folks, but before yesterday I never saw that tools, so I want to examinee how can I use them in my projects.
Ciao!
Thursday, July 12, 2007
Helpful tools n°1
Yesterday's evening I was navigating and writing some code, line after line, I took a tour on the SharpDevelop Web Site, I love that tool, in the past years frequently I took a tour in the source code, to learn, to see what has been done.
So I went to the SharpDevelop Wiki and I found a wonderful online tool, a Code Converter. The tool is exposed as Web service and makes use of NRefactory to convert code.
The link is http://codeconverter.sharpdevelop.net/Default.aspx here you can find:
- a class converter:
http://codeconverter.sharpdevelop.net/Convert.aspx
the supported convertsions are:- C# to VB.NET
- C# to Boo
- VB.NET to C#
- VB.NET to Boo
- a snippet converter:
http://codeconverter.sharpdevelop.net/SnippetConverter.aspx
the supported convertions are C# to VB.NET and vice versa. - a code formatter:
http://codeconverter.sharpdevelop.net/FormatCode.aspx
supports ASP/XHTML, BAT, Boo, Coco, C++.NET, C#, HTML, Java, JavaScript, Patch, PHP, TeX, VBNET, XML
It's possible too to use these features in client applications directly using and calling the web service.
As example I tried to format and colorize an xml chunk as:
<configuration target="StandardDatabaseConfig">
<provider name="testProvider" refTo="XmlProvider, TestLib.Providers" />
</configuration>
the result is:
1: <configuration target="StandardDatabaseConfig">
2: <provider name="testProvider" refTo="XmlProvider, TestLib.Pr
oviders" />
3: </configuration>
Fantastic tool!
Ciao!
AJAX and Server.Transfer battles 2° round
Yesterday, as I said in the previous post, I was fighting with some interesting features of ASP.NET Ajax 1.0. My situation was:
I had two ASP.NET pages, Page1 and Page2 configured as follow:
- Page1 acts as the Web Site home page
- Page2, in a different dircetory, acts as a chid, content page
Page1, redirects, via Server.Transfer, to child pages as Page2. Page2 contains an UpdatePanel and some DropDownLists controls.
Here is the problem, when Page2 take control, the "ajaxed" controls works fine the first time, but next time it doesn't. The exception throwed was:
Sys.WebForms.PageRequestManagerErrorException: unknown error ocurred while processing the request on the server. The status code returned from the server was: 404
So after hours spent looking for a solution, an example, or anything else could help me, I found this post http://forums.asp.net/p/1078772/1788445.aspx, the situation explained is the same as above.
The problem I experienced was that Page2 after load, mantains the correct form action, but after the first call then, the action became incorrect and no actions could be performed. So I tried to find a solution in many ways:
- searching if the client-page-content remains the same between the first well-done call and the second one
- because the ajaxed dropdown was outside the UpdatePanel, I tried to modify the related UpdatePanel Trigger
After I tried many solutions, I found very helpful the solution provied in the post. The solution is to add a Client-Side Javascript script to attach a custom function to the PageRequestManager to handle the EndRequest. There change the form action so the action remains the same across any ajax content refresh and any postback.
this is the code:
<script type="text/javascript"><!--//
function EndRequestHandler()
{
theForm.action = "../Folder1/Page2.aspx";
theForm._initialAction = theForm.action;
}
if( typeof(Sys) != "undefined" )
{
EndRequestHandler();
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
}
//-->
</script>
Because I spent so much time over this, I think this could be helpful and useful to others, without spending time to looking for a solution!
Ciao!