Hi guys - I've been struggling with this one for a while, the scenario seems very basic but I've spent several hours on this and run into what seems like NHibernate bugs..
Here's the situation. I have a class called "Price" which is implemented like this:
[Serializable] public class Price : IComparable, IFormattable, IComparable<int>, IEquatable<int> { public static implicit operator Price(int cents); public static implicit operator int(Price price); public static bool operator ==(Price x, Price y); public static bool operator !=(Price x, Price y); public int CompareTo(object obj); public int CompareTo(int other); public bool Equals(int other); }
As you can see, the compiler will treat Price exactly like an integer. I can say:
Price p = 500; //p is $5.00
...as well as compare a Price object to other Price objects or to ints.
In ActiveRecord, I'd like to have this:
[Property(NotNull = true, ColumnType = "Int32")] public Price VendorFees { get { return vendorfees; } set { vendorfees = value; } }
This seems simple enough, and actually the above code works when you Create or Update a record, however it causes an exception when you load. Under the covers, this appears to be an NHibernate bug. When NHibernate hydrates an object, in ReflectionOptimizer.cs there's a function called GenerateSetPropertyValuesMethod. This method actually builds IL code (pretty slick) which will loop through the value array from the database and set it to the appropriate setters on the object. However, there's a bug in this code that assumes the DB type and the "setter" type are exactly the same. The setter is never even called on my object, I just get an exception that says "Cannot cast Website.Price to System.Int32" (which happens when the IL code is invoked).. So in my opinion, that's an NHibernate bug however I don't see them fixing this.
The work-around I'm exploring is to get NHibernate to hydrate this column as a "Price" in the first place. The method I'm trying to use would be to do something like this:
[Property(NotNull = true, ColumnType = "Website.Price,Website", SqlType = "integer")] public Price VendorFees { get { return vendorfees; } set { vendorfees = value; } }
I believe this would work, however, Active Record appears to configure this column as a serializable type and wants to map it to a byte array in the DB. When AR is building the Insert command, I get an exception saying the parameter type was bytea but the data was an integer.
Can anyone point me in the right direction? I'm totally lost on this one. Thanks!!
Mike
|