1
votes

I have problem with CustomType in Fluent NHibernate. I have to save as Json a dictionary to my database. I created a customType for this that implements IUserType interface. There is no problem to save dictionary to database for first time, but when i try to update collection, nHibernate dont set a property as dirty and dont update it.

My Equals and GetHashCode methods

    public new bool Equals(object x, object y)
    {
        if (x == null && y == null)
            return true;

        if (x == null || y == null)
            return false;

        if (!(x is IDictionary<K, Z>) || !(y is IDictionary<K, Z>))
            return false;



        var dic1 = (x as IDictionary<K, Z>).OrderBy(z=> z.Key);
        var dic2 = (y as IDictionary<K, Z>).OrderBy(z => z.Key);

        return dic1.SequenceEqual(dic2);
    }

    public int GetHashCode(object x)
    {
        if (x == null)
            return 0;

        return x.GetHashCode();
    }

The objects passed to equals method are always the same (recently modified) two object. Anyone have a idea what i'm doing wrong ?

Rest of IUserType implementation code:

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        if (names.Length != 1)
            throw new InvalidOperationException("Only expecting one column...");

        var val = rs[names[0]] as string;

        if (val != null && !string.IsNullOrWhiteSpace(val))
        {
            return JsonConvert.DeserializeObject<T>(val, JSonSerializableTypeSerializer.Settings);
        }

        return null;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var parameter = (DbParameter)cmd.Parameters[index];

        if (value == null)
        {
            parameter.Value = DBNull.Value;
        }
        else
        {
            parameter.Value = JsonConvert.SerializeObject(value, JSonSerializableTypeSerializer.Settings);
        }
    }

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

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

    public bool IsMutable
    {
        get { return true; }
    }
1
You mean, your IUserType.Equals implementation always get the same object reference for x and y? And what are your returning for IsMutable?Frédéric
Your Replace implementation would causes issues if you work with detached entities. It should copy original to target for supporting Merge. Your Assemble and Disassemble implementations will cause issues if you use second level cache. They should at least yield deep copies, but maybe would it be better to cache (disassemble) the JSon serialization instead and de-serialized it on assemble. See IUserType comments.Frédéric

1 Answers

1
votes

Maybe I am wrong, but I guess you have returned false while implementing IUserType.IsMutable.

Since your user type returns a Dictionary, which is a mutable type, and which you do indeed mutate, your user type must return true for its IsMutable property.