Converting string to double in fluent-nhibernate mapping
Asked Answered
S

3

6

I have a sql table with a string column that could contain null, empty string or a double value. I want to map this column to a C# property that is a double, defaulting to zero when the column is null or empty. Can I do this with a fluent-nhibernate mapping? I tried this:

Map(p => p.doubleProperty).CustomSqlType("varchar(20)").CustomType("double").Default("0");

and variations on this theme but I always get an error that the conversion failed.

Sprag answered 7/7, 2011 at 16:40 Comment(0)
S
5

For now I've gone with a custom type which allows me to use

      Map(p=>p.doubleProperty).CustomType<DoubleString>();

Which will do for my current needs.

I'll leave the question open for now in case someone comes up with an easier solution.

Code for the DoubleString type is below.

public class DoubleString : IUserType
{
    public new bool Equals(object x, object y)
    {
        if (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 NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var valueToGet = NHibernateUtil.String.NullSafeGet(rs, names[0]) as string;
        double returnValue = 0.0;
        double.TryParse(valueToGet, out returnValue);
        return returnValue;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        object valueToSet = ((double)value).ToString();
        NHibernateUtil.String.NullSafeSet(cmd, valueToSet, index);
    }

    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 DeepCopy(cached);
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public SqlType[] SqlTypes
    {
        get
        {
            return new[] { new SqlType(DbType.String) };
        }
    }

    public Type ReturnedType
    {
        get { return typeof(double); }
    }

    public bool IsMutable
    {
        get { return true; }
    }
}
Sprag answered 8/7, 2011 at 12:7 Comment(2)
Great, this solved a case where I had to persist a custom struct as a string in the database! I'd greatly appreciate if you have any clues on how to modify the above so it works with Nullable<?> types though. Is it necessary to change it to work with nullables or I need only to play with the user type convention?Brebner
Its a very nice answer. In my case, I had to change the ToString() on line 40 to: .ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US")); because the ToString() changes the double from, e.g. 1.23 to 1,23 and the SQL didn't accepts it. With the culture it keeps the dot instead of the comma.Belicia
A
1

I would just map this to a string and in your entity have a property that is a double that does the conversion. Seems easier and cleaner than doing it in the mapping.

Maybe something like this:

public double Price
{
    get
    {
        double price = -1.0;
        Double.TryParse(stringProperty, out price);
        return price;
    }
    set { stringProperty = value.ToString(); }
}
Anisometric answered 7/7, 2011 at 18:38 Comment(2)
I'm not so sure it's cleaner, I'd need a string property for NH to use when saving and a double property to use when accessing it from code. That's if I understand what you are suggesting correctly. If I just have one double property then NH saves it as a double and not as a string.Sprag
touché ... I meant to take the cleaner part out. Cleaner as far as your mapping is concerned but not your entity. In this solution you would have a private string variable and a public double propertyAnisometric
B
0

I solved kind of the same problem using two Properties which both referred to the same private variable. In my example the database contains a varchar which is NOT USED or ACTUAL, i therefor wanted a bool in my application.

    private bool _myBool= true;

    public virtual bool MyBool{ get { return _myBool; } set { _myBool= value; } }

    public virtual string MyString
    {
        get { return _myBool ? "ACTUAL" : "NOT USED"; }
        set { _myBool= value.Equals("NOT USED"); }
    }
}
Befoul answered 14/7, 2011 at 5:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.