Isn't there a risk with versions date limited to the precision of second

Topics: General, Troubleshooting
Sep 18, 2014 at 7:56 AM
Related to Sebastien's correction
Isn't there a risk that we got now several records with equivalent dates ?
Couldn't we use the millisecond part to compare when present on each side ?
Sep 18, 2014 at 8:02 AM
Edited Sep 18, 2014 at 8:03 AM
All this would be easier to fix if we were not limited to a dozen of standard objects (int, string, datetime, decimal, etc.) by NHibernate and we could create real objects as Date, Money, etc., all managed by the ORM.
May be this is already working with infoset.

I hope the guies working on ASPNET VNext which is accepting ORMs and dependency injection will take care to bring back object oriented power in ASPNET.
Sep 18, 2014 at 8:07 AM

NHibernate is not the limiting factor. The database types are.

Sep 18, 2014 at 8:15 AM
Edited Sep 18, 2014 at 8:16 AM
Concerning this second part of my thread, sorry but you missed the point I was pointing.
With several databases targeted you will always have problems, (see recent issues reports for MySQL), it is an abstraction problem usually solved in OOL by creating types corresponding to your needs and able to assume a storage independency.
You have a base type and you simply store it, no necessity to add hundred code lines to test whatever is the PB with DB.
This is not the case with NH.
Sep 18, 2014 at 6:10 PM
Edited Sep 18, 2014 at 6:20 PM
@JasperD I have tried but sorry to much problems, certainly something for superior spirits
1) In orchard as in DefaultDataMigrationInterpreter
public static string ConvertToSqlValue(object value) {
            if ( value == null ) {
                return "null";
            TypeCode typeCode = Type.GetTypeCode(value.GetType());
            switch (typeCode) {
                case TypeCode.Empty:
                case TypeCode.Object:
                case TypeCode.DBNull:
                case TypeCode.String:
                case TypeCode.Char:
                    return String.Concat("'", Convert.ToString(value).Replace("'", "''"), "'");
                case TypeCode.Boolean:
                    return (bool) value ? "1" : "0";
                case TypeCode.SByte:
                case TypeCode.Int16:
                case TypeCode.UInt16:
                case TypeCode.Int32:
                case TypeCode.UInt32:
                case TypeCode.Int64:
                case TypeCode.UInt64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                    return Convert.ToString(value, CultureInfo.InvariantCulture);
                case TypeCode.DateTime:
                    return String.Concat("'", Convert.ToString(value, CultureInfo.InvariantCulture), "'");

            return "null";
2) Then in NH the UserType and an UserTypeConvention<T> not totally work.
But if you can help me, it would be welcome, I was trying to implement a Money type which could contain currency and decimal values, this is very common in e-commerce sites and crms.
And it has been impossible, part of my implementation still commented in my code
public struct Money :   IEquatable<Money>,
        #region ICompositeUserType (for NHibernate)
        public Type ReturnedClass { get { return typeof(Money); } }
        public object DeepCopy(object value) { return value; }
        public bool IsMutable { get { return false; } }

        public Int64 Units { get { return _units; } }
        public Int32 DecimalFraction { get { return _decimalFraction; } }
        public string Iso3LetterCode { get { return _currency.Iso3LetterCode; } }

        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)
            return x.GetHashCode();

        public object Replace(object original, object target, NHibernate.Engine.ISessionImplementor session, object owner)
            return original;

        public object NullSafeGet(IDataReader dr, string[] names, NHibernate.Engine.ISessionImplementor session, object owner)
            object obj0 = NHibernateUtil.Int64.NullSafeGet(dr, names[0]);
            object obj1 = NHibernateUtil.Int32.NullSafeGet(dr, names[1]);
            object obj2 = NHibernateUtil.Int32.NullSafeGet(dr, names[2]);
            if (obj0 == null || obj1 == null || obj2 == null) return null;
            Int64 unit = (Int64)obj0;
            Int32 decimalFraction = (Int32)obj1;
            string wcurrency = (string)obj1; 
            return new Money(unit, decimalFraction,Currency.FromIso3LetterCode(wcurrency));
        public void NullSafeSet(IDbCommand cmd, object obj, int index, bool[] settable, NHibernate.Engine.ISessionImplementor session)
            if (obj == null)
                ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
                ((IDataParameter)cmd.Parameters[index + 1]).Value = DBNull.Value;
                ((IDataParameter)cmd.Parameters[index + 2]).Value = DBNull.Value;
                Money amount = (Money)obj;
                ((IDataParameter)cmd.Parameters[index]).Value = amount._units;
                ((IDataParameter)cmd.Parameters[index + 1]).Value = amount._decimalFraction;
                ((IDataParameter)cmd.Parameters[index + 2]).Value = amount._currency.Iso3LetterCode;
        public string[] PropertyNames
            get { return new string[] { "Units", "DecimalFraction", "Iso3LetterCode" }; }
        public NHibernate.Type.IType[] PropertyTypes
                return new NHibernate.Type.IType[] {
                NHibernateUtil.Int64, NHibernateUtil.Int32,NHibernateUtil.String };
        public object GetPropertyValue(object component, int property)
            Money amount = (Money)component;
            if (property == 0)
                return amount._units;
            else if (property == 1)
                return amount._decimalFraction;
                return amount._currency.Iso3LetterCode;
        public void SetPropertyValue(object comp, int property, object value)
            throw new Exception("Immutable!");

        public object Assemble(object cached, NHibernate.Engine.ISessionImplementor session, object owner)
            return cached;
        public object Disassemble(object value,NHibernate.Engine.ISessionImplementor session)
            return value;
    #endregion // ICompositeUserType
This I have been doing it easily in webforms using simple ago, and before using C++ and various databases today no more used.

Concerning DB Abstraction, seems that you have not understood what I was saying, certainly because it was badly explained.
But yes sometimes the system objects can have a DB storage that would fit any database, for exemple a decimal is easy to represent with some long objects similar to registers and stored in any DB.

EDIT: so sometimes it is better to defined a different object than the one used in the language basic types.
Sep 18, 2014 at 7:11 PM
Edited Sep 18, 2014 at 7:25 PM
I put the DataMigrationInterpreter as an example of Orchard limits: you can't define a 'column' with a custom type, because Orchard, on several places, uses this kind of statement
TypeCode typeCode = Type.GetTypeCode(value.GetType());
            switch (typeCode) {
and this is even in the code from what I remember.
So with this code, how do you deal with a price column expressed in Money ?

Concerning NH, in mapping I see that your code convert a Point in a string value, so it stores simply a string in NH, would it work will 3 values as I need for Money type ?
This has been a blocking point when I tried to implement this in Orchard 1.6, I would say that I decided that the NH way was not working at that time.
Seems that you also modified Orchard code in your fork ? Could it run with 1.x without applying some patch ?
Sep 18, 2014 at 7:30 PM
Will give a try. Thanks.
Sep 18, 2014 at 8:20 PM
Edited Sep 18, 2014 at 8:21 PM
I don't remember the tutorial I followed 2 years ago, yes the Missing ICompositeUserType is because all has been commented so no more needed.
I will try but being quite busy, I will need some weeks to go back to this.

And back to the orchard integration, have you got no show stopper with the switch based on the Type;getTypeCode ? From what I remember it was blocking in many places when you need to use your custom type in parts ?

We are very far from my inner subject :)
Sep 24, 2014 at 12:32 PM
Ok, will try it certainly next week.
My Money class is .... more complicated :)