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, "|"); } 
         }
4
  • 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<Attachment>) but it could be used for searching (subqueries). Anyhow, if you want to use IList<string> separated table is still the best option, I'd say. Commented Nov 1, 2014 at 6:33
  • @RadimKöhler my question is purely for List<string> and has nothing to do with List<Files>... wont the user type be better?? Commented Nov 1, 2014 at 16:01
  • If I'd have an answer, I would give it to you. My point is, that 1) IList<string> 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... Commented Nov 1, 2014 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... Commented Nov 1, 2014 at 16:07

1 Answer 1

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();
    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.