NHibernate 3.2 By Code ClassMapping for Version Property - c#

What is the correct way to map an timestamp column in an SQL Server 2008 database using NHibernate's new code based mappings?
I have the property in my class defined as byte[] and I'm using the following mapping in my ClassMapping file:
Version(x => x.RowVersion, mapping =>
mapping.Generated(VersionGeneration.Always));
However, NHibernate is expecting an integer based on this mapping (throws an exception on inserts). If I explicitly specify the mapping type as byte[], I get an exception stating: "System.ArgumentOutOfRangeException: Expected type implementing IUserVersionType
Parameter name: persistentType".
What is the proper way to map an auto updating timestamp column with the new NHibernate code based mappings?
---EDIT
I think I have it narrowed down that I need to set the Type on the mapping to BinaryType (an NHibernate Type that implements IVersionType), but BinaryType doesn't have a public constructor...I think I'm out of ideas.

If you grab the NHib source code, there's a class in a test project that will help you with what you need: NHibernate.Test.VersionTest.Db.MsSQL.BinaryTimestamp. Basically, you have to give it a custom type it can use to convert the value. Be default NHib expects the value to be an int (look at seciont 5.1.7 of the nhib docs). If you use an int/bigint as your version column, you will not need a custom type.
The custom class (lifted from NHib source code):
public class BinaryTimestamp : 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[] { new SqlType(DbType.Binary, 8) }; }
}
public int Compare(object x, object y)
{
var xbytes = (byte[])x;
var ybytes = (byte[])y;
return CompareValues(xbytes, ybytes);
}
bool IUserType.Equals(object x, object y)
{
return (x == y);
}
#endregion
private static int CompareValues(byte[] x, byte[] y)
{
if (x.Length < y.Length)
{
return -1;
}
if (x.Length > y.Length)
{
return 1;
}
for (int i = 0; i < x.Length; i++)
{
if (x[i] < y[i])
{
return -1;
}
if (x[i] > y[i])
{
return 1;
}
}
return 0;
}
public static bool Equals(byte[] x, byte[] y)
{
return CompareValues(x, y) == 0;
}
}
A sample mapping using that class:
public class Car
{
public virtual long CarId { get; set; }
public virtual string Name { get; set; }
public virtual byte[] LastModified { get; set; }
public override string ToString()
{
return string.Format("Id: {0}, Name: {1}, Last Modified: {2}", CarId, Name, LastModified);
}
}
public class CarMap : ClassMapping<Car>
{
public CarMap()
{
Table("Cars");
Id(car => car.CarId, mapper => mapper.Generator(Generators.Identity));
Property(car => car.Name);
Version(car => car.LastModified, mapper =>
{
mapper.Generated(VersionGeneration.Always);
mapper.Type<BinaryTimestamp>();
});
}
}

We also are using byte[] Version { get; } for version implementation.
Here is out mappings:
Version(x => x.Version)
.Nullable()
.CustomSqlType("timestamp")
.Generated.Always()
;
Also for more details please see this link

In the case of a ConventionModelMapper I ended up using the following..
ConventionModelMapper mapper = new ConventionModelMapper();
//...other mappings
mapper.Class<Entity>(map => map.Version(e => e.Revision, m =>
{
m.Generated(VersionGeneration.Always);
m.UnsavedValue(null);
m.Type(new BinaryBlobType());
m.Column(c =>
{
c.SqlType("timestamp");
c.NotNullable(false);
});
}));

Related

set multiple return value for method declaration

I have a function as below:
public var UpdateMapFetcher(int stationID, int typeID)
I need this function to return either string or int.
My return value is set as below
if (finaloutput == "System.String")
{
// param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
returnvalue = returnvalue.ToString();
return returnvalue;
}
else if (finaloutput == "System.Int32")
{
int a=0;
a = Convert.ToInt32(returnvalue);
return a;
}
How to have either one data type as return value in dynamic environment.
My intuition tells me, that you are trying to convert string value to some type. In that case you can use:
public T UpdateMapFetcher<T>(int stationID)
{
//var someValue = "23";
return (T)Convert.ChangeType(someValue, typeof(T));
}
//then
var typed = UpdateMapFetcher<int>(6);
In case you don't know T, you can use mapping (0-int, 1-string, etc.):
public object UpdateMapFetcher(int stationID, int type)
{
var typeMap = new []{ typeof(int), typeof(string)};
//var someValue = "23";
return Convert.ChangeType(someValue, typeMap[type]);
}
//then
var untyped = UpdateMapFetcher(6, 0/*0 is int*/);
if (untyped.GetType() == typeof(int))
{ /*is int*/
}
Another solution is to use implicit conversions:
public class StringOrInt
{
private object value;
public ValueType Type { get; set; }
public static implicit operator StringOrInt(string value)
{
return new StringOrInt()
{
value = value,
Type = ValueType.String
};
}
public static implicit operator StringOrInt(int value)
{
return new StringOrInt()
{
value = value,
Type = ValueType.Int
};
}
public static implicit operator int(StringOrInt obj)
{
return (int)obj.value;
}
public static implicit operator string(StringOrInt obj)
{
return (string)obj.value;
}
}
public enum ValueType
{
String,
Int
}
And then (simplified):
public static StringOrInt UpdateMapFetcher(int stationID, int typeID)
{
if (typeID == 0)
return "Text";
return 23;
}
private static void Main(string[] args)
{
var result = UpdateMapFetcher(1, 1);
if (result.Type == ValueType.String) { }//can check before
int integer = result;//compiles, valid
string text = result;//compiles, fail at runtime, invalid cast
}
you can return an object. You'd have to subsequently check for types in your consuming method. I assume that won't be a problem in your usecase.
your method signature is therefore:
public object UpdateMapFetcher(int stationID, int typeID)
You also have the option of using the out keyword, which permits you to accept both into variables and check after the function has been called.
public void UpdateMapFetcher(int stationID, int typeID, out int intValue, out string strValue)
// or int return val and out string value
public int UpdateMapFetcher(int stationID, int typeID, out string strValue)
With the use appearing something like this:
int intVal;
string strVal;
UpdateMapFetcher(stationID, typeID, out intVal, out strVal);
if (strVal != null)
{
doSomethingWithString(strVal);
}
else
{
doSomethingWithInt(intVal);
}
Frankly, I would just return a Tuple, with string being non-null indicating string value to use, and null as indicator for int return
public Tuple<string, int> UpdateMapFetcher(int stationID, int typeID) {
if (finaloutput == "System.String")
{
// param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
returnvalue = returnvalue.ToString();
return new Tuple<string, int>(returnvalue, 0);
}
else if (finaloutput == "System.Int32")
{
int a=0;
a = Convert.ToInt32(returnvalue);
return new Tuple<string, int>(null, a);
}
}
On consumer side
var rc = UpdateMapFetcher( .... );
if (rc.Item1 != null) {
// code to use string value
} else {
// code to use int value
}
I would choose to return an object of new class which might look like this:
class Result {
public string StringValue { get; }
public string Int32Value { get; }
public bool IsString { get; }
public bool IsInt32 { get; }
public Result(string value) {
StringValue = value;
IsString = true;
}
public Result(int value) {
Int32Value = value;
IsInt32 = true;
}
}
This way you can check which Type is it by using Isxxx property. You can also enhance this with validation in value geters. F. e., for string it might look like this:
public string StringValue {
get {
if (IsString)
return m_stringValue;
throw new InvalidOperationException("Value is not a string.");
}
}
You can't really do exactly that, but there are several ways to do more or less what you want. You'd probably be better off change the design a little though.
Two ideas:
Either change your code to use two different methods, and call each of them as needed instead.
..Or return an object, which you can cast however you like..
..Or, use a generic method with TypeDescriptor, like the following.
Note that we here convert the value to string first even if it was an int, since we can then use a common method ConvertFromString() to convert it to whatever type T was.
public T UpdateMapFetcher<T>(int stationID, int typeID) {
// To allow parsing to the generic type T:
var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
if(converter != null)
{
return (T)converter.ConvertFromString(returnvalue.ToString());
}
else
{
return default(T);
}
}
Usage:
var result = MyExtensions.UpdateMapFetcher<string>(1, 2);
or:
var result = MyExtensions.UpdateMapFetcher<int>(1, 2);
You can return Object and cast to type which you want.
public Object UpdateMapFetcher(int stationID, int typeID)
if (finaloutput == "System.String")
{
// param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
returnvalue = returnvalue.ToString();
return returnvalue;
}
else if (finaloutput == "System.Int32")
{
int a=0;
a = Convert.ToInt32(returnvalue);
return a;
}
A type that can contain either one type or another is usually called (unsurprisingly) Either. It is a special case of a sum type, basically a discriminated union, tagged union, or disjoint union with exactly two cases (instead of an arbitrary number).
Unfortunately, there does not exist an implementation of an Either type in the standard libraries, but there are plenty of implementations to be found on Google, GitHub, and elsewhere … and porting one of the existing implementations from e.g. Haskell or Scala isn't that hard, either.
It looks a bit like this (forgive my code, I don't actually know C♯ that well):
using System;
abstract class Either<A, B>
{
public abstract bool IsLeft { get; }
public abstract bool IsRight { get; }
public abstract A Left { get; }
public abstract B Right { get; }
public abstract A LeftOrDefault { get; }
public abstract B RightOrDefault { get; }
public abstract void ForEach(Action<A> action);
public abstract void ForEach(Action<B> action);
public abstract void ForEach(Action<A> leftAction, Action<B> rightAction);
private sealed class L : Either<A, B>
{
private A Value { get; }
public override bool IsLeft => true;
public override bool IsRight => false;
public override A Left => Value;
public override B Right { get { throw new InvalidOperationException(); } }
public override A LeftOrDefault => Value;
public override B RightOrDefault => default(B);
public override void ForEach(Action<A> action) => action(Value);
public override void ForEach(Action<B> action) {}
public override void ForEach(Action<A> leftAction, Action<B> rightAction) => leftAction(Value);
internal L(A value) { Value = value; }
}
private sealed class R : Either<A, B>
{
private B Value { get; }
public override bool IsLeft => false;
public override bool IsRight => true;
public override A Left { get { throw new InvalidOperationException(); } }
public override B Right => Value;
public override A LeftOrDefault => default(A);
public override B RightOrDefault => Value;
public override void ForEach(Action<A> action) {}
public override void ForEach(Action<B> action) => action(Value);
public override void ForEach(Action<A> leftAction, Action<B> rightAction) => rightAction(Value);
internal R(B value) { Value = value; }
}
public static Either<A, B> MakeLeft(A value) => new L(value);
public static Either<A, B> MakeRight(B value) => new R(value);
}
And you'd use it like this:
static class Program
{
public static void Main()
{
var input = Console.ReadLine();
int intResult;
var result = int.TryParse(input, out intResult) ? Either<int, string>.MakeLeft(intResult) : Either<int, string>.MakeRight(input);
result.ForEach(r => Console.WriteLine("You passed me the integer one less than " + ++r), r => Console.WriteLine(r));
}
}

Mapping a custom type property in Fluent NHibernate

I have a database that saves an Id of an item that is stored in another system and deserialized to an object in code. I am trying to use Fluent NHibernate to build a Domain Model entity that is composed of data from the database and the external service. An example will explain this better. In the database I have a table looking like this:
CREATE TABLE entities
(
id integer NOT NULL,
custom_thing text NOT NULL,
CONSTRAINT entities_id_pk PRIMARY KEY (id)
);
It is PostgreSQL but the problem is not database specific. Now in the code I have these classes:
class Entity
{
public virtual int Id { get; set; }
public virtual CustomThing CustomThing { get; set; }
}
class CustomThing
{
public string Id { get; set; }
public string Name { get; set; }
}
I'm trying to use a CustomMap to define the mapping:
class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
Table("entities");
Id(e => e.Id, "id").GeneratedBy.Assigned();
// Map(e => e.CustomThing, "custom_thing");
}
}
The question is: how can I map the CustomThing? Here's a program trying to map the Entity class (need FluentNHibernate package and NpgSQL if run against PostgreSQL database). For simplicity I just create instances of CustomThing in code:
class Program
{
// How to use this in mapping?
static CustomThing[] _customThings =
{
new CustomThing {Id = "abc", Name = "ABC"},
new CustomThing {Id = "def", Name = "DEF"}
};
static void Main()
{
using (ISessionFactory sessionFactory = Fluently.Configure()
.Database(PostgreSQLConfiguration.Standard
.ConnectionString(
#"Server=localhost; Database=test_nhibernate; User Id=postgres; Password=little_secret;"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Entity>())
.BuildSessionFactory())
{
using (ISession session = sessionFactory.OpenSession())
{
var entity = session.Get<Entity>(1);
Console.WriteLine($"{entity?.Id} {entity?.CustomThing?.Name}");
}
}
Console.ReadLine();
}
}
The output is of course only the Id property value because mapping for CustomThing is not defined. Is it possible to configure the mapping so that I can pass parameters to it and map custom_thing column values to objects in _customThings by Id property somehow?
Yes, you can do it either by save the Id, and get rest of data in your code, or put every thing in your mapper to return an object to you, if you select the second option you can follow this code:
[Serializable]
public class CustomThingUserType : IUserType {
public new bool Equals(object x, object y) {
if (object.ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
return x.Equals(y);
}
public int GetHashCode(object x) {
if (x == null)
return 0;
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner) {
if (names.Length == 0)
throw new ArgumentException("Expecting at least one column");
int id = (int)NHibernateUtil.Int32.NullSafeGet(rs, names[0]);
var obj = new CustomThing { Id = id };
// here you can grab your data from external service
return obj;
}
public void NullSafeSet(IDbCommand cmd, object value, int index) {
var parameter = (DbParameter)cmd.Parameters[index];
if (value == null) {
parameter.Value = 0;
}
else {
parameter.Value = ((CustomThing)value).Id;
}
}
public object DeepCopy(object value) {
return value;
}
public object Replace(object original, object target, object owner) {
return original;
}
public object Assemble(object cached, object owner) {
return cached;
}
public object Disassemble(object value) {
return value;
}
public SqlType[] SqlTypes {
get {
return new SqlType[] { new SqlType(DbType.Int32) };
}
}
public Type ReturnedType {
get { return typeof(CustomThing); }
}
public bool IsMutable {
get { return false; }
}
}

nhibernate : read write list of string

I know I can read write list of string like below using nhibernate
HasMany(x => x.Attachments)
.KeyColumn("RowId")
.Table("PostTable").Element("PostKey");
But this creates an extra table, is there a way e.g. UserType or something else, so that we can directly write to list... if yes any example of custom UserType using nhibernate?? with sample code...
I also want that If i add value to list that also should be saved. I have seen below example code which breaks in case we add value to list...
private virtual string StringValue
public virtual IList<string> valueList
{
get { return StringValue; }
set { StringValue = string.Join(value, "|"); }
}
You can do this with IUserType like so:
public class DelimitedList : IUserType
{
private const string delimiter = "|";
public new bool Equals(object x, object y)
{
return object.Equals(x, y);
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var r = rs[names[0]];
return r == DBNull.Value
? new List<string>()
: ((string)r).SplitAndTrim(new [] { delimiter });
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
object paramVal = DBNull.Value;
if (value != null)
{
paramVal = ((IEnumerable<string>)value).Join(delimiter);
}
var parameter = (IDataParameter)cmd.Parameters[index];
parameter.Value = paramVal;
}
public object DeepCopy(object value)
{
return value;
}
public object Replace(object original, object target, object owner)
{
return original;
}
public object Assemble(object cached, object owner)
{
return cached;
}
public object Disassemble(object value)
{
return value;
}
public SqlType[] SqlTypes
{
get { return new SqlType[] { new StringSqlType() }; }
}
public Type ReturnedType
{
get { return typeof(IList<string>); }
}
public bool IsMutable
{
get { return false; }
}
}
Then define the IList<string> property as type="MyApp.DelimitedList, MyApp".
NOTE: SplitAndTrim is a string extension with various overrides that I created. Here is the core method:
public static IList<string> SplitAndTrim(this string s, StringSplitOptions options, params string[] delimiters)
{
if (s == null)
{
return null;
}
var query = s.Split(delimiters, StringSplitOptions.None).Select(x => x.Trim());
if (options == StringSplitOptions.RemoveEmptyEntries)
{
query = query.Where(x => x.Trim() != string.Empty);
}
return query.ToList();
}

Generic IComparer for sorting different objects in different properties

I'm trying to sort an array of objects with IComparer.
I wrote the code but it works only with the particular object. e.g.:
for this class
public class Cars
{
public string Name { get; set; }
public string Manufacturer { get; set; }
public int Year { get; set; }
public Cars(string name, string manufacturer, int year)
{
Name = name;
Manufacturer = manufacturer;
Year = year;
}
}
My code looks like:
class MySort
{
public class SortByYears : IComparer
{
int IComparer.Compare(Object x, Object y)
{
Cars X = (Cars)x, Y = (Cars)y;
return (X.Year.CompareTo(Y.Year));
}
}
public class SortByName : IComparer
{
int IComparer.Compare(Object x, object y)
{
Cars X = (Cars)x, Y = (Cars)y;
return (X.Name.CompareTo(Y.Name));
}
}
public class SortByManyfacturer : IComparer
{
int IComparer.Compare(object x, object y)
{
Cars X = (Cars)x, Y = (Cars)y;
return (X.Manufacturer.CompareTo(Y.Manufacturer));
}
}
}
But if I add another class with different properties it will be useless.
So is there any chance to modify this code so that it worked for objects with different properties?
class SortComparer<T> : IComparer<T>
{
private PropertyDescriptor PropDesc = null;
private ListSortDirection Direction =
ListSortDirection.Ascending;
public SortComparer(object item,string property,ListSortDirection direction)
{
PropDesc = TypeDescriptor.GetProperties(item)[property];
Direction = direction;
}
int IComparer<T>.Compare(T x, T y)
{
object xValue = PropDesc.GetValue(x);
object yValue = PropDesc.GetValue(y);
return CompareValues(xValue, yValue, Direction);
}
private int CompareValues(object xValue, object yValue,ListSortDirection direction)
{
int retValue = 0;
if (xValue is IComparable) // Can ask the x value
{
retValue = ((IComparable)xValue).CompareTo(yValue);
}
else if (yValue is IComparable) //Can ask the y value
{
retValue = ((IComparable)yValue).CompareTo(xValue);
}
// not comparable, compare String representations
else if (!xValue.Equals(yValue))
{
retValue = xValue.ToString().CompareTo(yValue.ToString());
}
if (direction == ListSortDirection.Ascending)
{
return retValue;
}
else
{
return retValue * -1;
}
}
}
Calling code:
Assuming a list named lst:
lst.Sort(new SortComparer<Cars>(lst[0],"YourPropertyName",ListSortDirection.Ascending));
You may leverage the Create method of Comparer<T> which takes a Comparison delegate and returns Comparer<T>.
var carnameComparer = Comparer<Cars>.Create((x, y) => x.Year.CompareTo(y.Year));
var carManufacturerComparer = Comparer<Cars>.Create((x, y) => x.Manufacturer.CompareTo(y.Manufacturer));
and for another type
var carsComparer = Comparer<SomeType>.Create((x, y) => x.SomeProperty.CompareTo(y.SomeProperty));
If you're in prior to .Net4.5 you can use the following CreateComparer method.
private static IComparer<T> CreateComparer<T>(Comparison<T> comparison)
{
return new ComparisonComparer<T>(comparison);
}
public class ComparisonComparer<T> : IComparer<T>
{
private Comparison<T> comparison;
public ComparisonComparer(Comparison<T> comparison)
{
if (comparison == null)
{
throw new ArgumentNullException("comparison");
}
this.comparison = comparison;
}
public int Compare(T x, T y)
{
return comparison(x, y);
}
}
Use an interface and use generic IComparer Interface instead of IComparer
public interface IObjectWithNameProperty
{
string Name {get; set;}
}
public class MyNameComparer : IComparer<IObjectWithNameProperty>
{
public int Compare(IObjectWithNameProperty x, IObjectWithNameProperty y)
{
...
}
}
public class Car: IObjectWithNameProperty
{
public string Name {get;set;}
...
}
public class Dog: IObjectWithNameProperty
{
public string Name {get;set;}
...
}
Here is another take based on terrybozzio's.
public class PropertyComparer<T> : IComparer<T> where T : new()
{
private PropertyDescriptor PropDesc = null;
private ListSortDirection Direction = ListSortDirection.Ascending;
public PropertyComparer(string property, ListSortDirection direction)
{
T item = new T();
PropDesc = TypeDescriptor.GetProperties(item)[property];
Direction = direction;
Type interfaceType = PropDesc.PropertyType.GetInterface("IComparable");
if (interfaceType == null && PropDesc.PropertyType.IsValueType)
{
Type underlyingType = Nullable.GetUnderlyingType(PropDesc.PropertyType);
if (underlyingType != null)
{
interfaceType = underlyingType.GetInterface("IComparable");
}
}
if (interfaceType == null)
{
throw new NotSupportedException("Cannot sort by " + PropDesc.Name +
". This" + PropDesc.PropertyType.ToString() +
" does not implement IComparable");
}
}
int IComparer<T>.Compare(T x, T y)
{
object xValue = PropDesc.GetValue(x);
object yValue = PropDesc.GetValue(y);
IComparable comparer = (IComparable)xValue;
if (Direction == ListSortDirection.Ascending)
{
return comparer.CompareTo(yValue);
}
else
{
return -1 * comparer.CompareTo(yValue);
}
}
}
The cleanest way is to define an interface that both object implement, then use that in the comparison. Otherwise you're going to have a mess of case statements depending on the
possible combination of objects:
public class SortByYears : IComparer
{
int IComparer.Compare(Object x, Object y)
{
if(x is Cars)
{
Cars X = (Cars)x
if(y is Cars)
{
Y = (OtherCars)y;
return (X.Year.CompareTo(Y.Year));
if(y is OtherCars)
{
Y = (OtherCars)y;
return (X.Year.CompareTo(Y.Year));
}
}
if(x is OtherCars)
{
... repeat upper block
}
}
}
Another approach would be using the generic IComparer interface and lambda expressions.
class CarComparer<T> : IComparer<Car> where T : IComparable<T>
{
private readonly Func<Car, T> _sortExpression;
public CarComparer(Func<Car, T> sortExpression)
{
_sortExpression = sortExpression;
}
public int Compare(Car x, Car y)
{
return _sortExpression(x).CompareTo(_sortExpression(y));
}
}
This class compares the Car's property passed in parameter in the constructor.
// Sort the cars by name
var nameCarComparer = new CarComparer<string>(car => car.Name);
Array.Sort(myArray, nameCarComparer);

NHibernate - Conversion failed when converting datetime from binary/varbinary string

Note, this is some ancient NHibernate installation! I have the following NHibernate class:
[Serializable]
[Class(Table = "SomeEvents")]
public class SomeEvent
{
[Property(Column="processDate")]
public DateTime? ProcessDate { get; set; }
}
When trying to update some events like:
using (ISession session = FDK_Hibernate_Manager.OpenSession())
{
IQuery query = session.CreateQuery(string.Format("FROM {0} e WHERE e.ContractId = :cid", typeof(ContractLeverconditiesEvent)));
query.SetInt32("cid", contractId);
foreach(var evnt in query.List().Cast<SomeEvent>())
{
evnt.ProcessDate = DateTime.Now;
session.SaveOrUpdate(evnt);
}
session.Flush();
}
I receive the following exception:
Conversion failed when converting datetime from binary/varbinary string.
So I basically guess that NHibernate doesn't understand my DateTime? yet. My NHibernate install doesn't have any fancy Nullables.NHibernate.NullableDateTimeType. So anyone has a clue to solve this ancient NHibernate issue?
I ended up with this (although it can require some work in error-checking and such :-))
Implement it using [Property(Column = "processDate", TypeType = typeof(NullableDateTime))]
class NullableDateTime : IUserType
{
#region IUserType Members
public new bool Equals(object obj, object obj2)
{
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public object DeepCopy(object value)
{
return value;
}
public bool IsMutable
{
get { return true; }
}
public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
{
object o = rs[names[0]];
if (o == DBNull.Value) return new Nullable<DateTime>();
else
return new Nullable<DateTime>(((System.Data.SqlTypes.SqlDateTime)o).Value);
}
public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
{
System.Data.Common.DbParameter parameter = (System.Data.Common.DbParameter)cmd.Parameters[index];
if (value == null)
{
parameter.Value = DBNull.Value;
return;
}
else
{
parameter.Value = new System.Data.SqlTypes.SqlDateTime((DateTime)value);
}
}
public Type ReturnedType
{
get { return this.GetType(); }
}
public NHibernate.SqlTypes.SqlType[] SqlTypes
{
get { return new NHibernate.SqlTypes.SqlType[] { new SqlDateTimeType() }; }
}
#endregion
}
public class SqlDateTimeType : NHibernate.SqlTypes.SqlType
{
public SqlDateTimeType() : base(System.Data.DbType.DateTime)
{
}
}
Unfortunately, you'll probably have to use a proxy value (magic number) for the null date. 1/1/1900 is a common choice. If you can map a private member (I don't use attributes), you could control the value through the public property:
public class SomeEvent
{
private DateTime _processDate; // map this
public SomeEvent()
{
_processDate = new DateTime(1900, 1, 1);
}
public DateTime? ProcessDate
{
get
{
if (_processDate == new DateTime(1900, 1, 1))
{
return null;
}
return _processDate;
}
set
{
_processDate = value ?? new DateTime(1900, 1, 1);
}
}
}

Categories

Resources