2

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, "|"); } 
         }
Community
  • 1
  • 1
harishr
  • 17,807
  • 9
  • 78
  • 125
  • 2
    *My view, from my experience...* I would not go this way. Because later, if your app will be successful, users will ask you for functionality to search by the value from the `Attachments`... And that will be very difficult. I do use entities everywhere. I.e. `Attachment` with 1) ID and 2) string Description... 3) and reference back to the holder. That way model becomes a bit more complex (IList) but it could be used for searching (subqueries). Anyhow, if you want to use `IList` separated table is still the best option, I'd say. – Radim Köhler Nov 01 '14 at 06:33
  • @RadimKöhler my question is purely for List and has nothing to do with List... wont the user type be better?? – harishr Nov 01 '14 at 16:01
  • If I'd have an answer, I would give it to you. My point is, that 1) `IList` should be stored in separate table. That table will hold the reference to the root entity (Holder_ID column), and the string value (value column). 2) If we are already there I would suggest to go even further. I would extend the table with its own surrogated key and treat it as an `Attachment` or `File` entity... But keep List of strings inlined... I do not see any advantage... Not sure if that helps... – Radim Köhler Nov 01 '14 at 16:04
  • 1
    And user types... Honestly, I never used any. Even if tried. At the end, I relaized that 1) pure entity 2) many-to-one and 3) one-to-many is enough in any scenario. It brings lot of advantages, like searching... – Radim Köhler Nov 01 '14 at 16:07

1 Answers1

1

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();
    }
harishr
  • 17,807
  • 9
  • 78
  • 125