2

I have a simple class with a IList<string> property. How to map this property in Fluent Nhibernate ?

[Serializable]
public class ExportTask
{
    private IList<string> _csvExportList = new List<string>();

    public ExportTask()
    {}

    public virtual IList<string> CsvExportList
    {
        get { return _csvExportList; }
        set { _csvExportList = value; }
    }
}

public class ExportTaskMap : SubclassMap<ExportTask>
{
    public ExportTaskMap()
    {           
        HasMany(x => x.CsvExportList)
               .Element("CsvExportList")
               .Cascade
               .AllDeleteOrphan();
    }
}

Following error occurs:

Initializing -failed to lazily initialize a collection of role: MyApp.Tasks.ExportTask.CsvExportList, no session or session was closed

When calling addrange on the collection:

var exportList = new List<string>()
                     {
                        {"item1"},
                        {"item2"}
                      };

CsvExportList.AddRange(exportList);

2 Answers 2

6

It truns out we can use AsList mapping with a column for the list index and allworks great. I wonder why there are no answers out there for this simple usecase. Hope it helps out someone.

public class ExportTaskMap : SubclassMap<ExportTask>
{
  public ExportTaskMap()
  {           
     HasMany(x => x.CsvExportList)
           .Element(@"CsvProperty")
           .KeyColumn(@"ExportTask_id")
           .Table(@"CsvExportProperties")
           .AsList(x => x.Column(@"CsvPropertyListIndex"))
           .Not.LazyLoad();
  }
}

And the mapped table will look like the following in the database.

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

This doesn't work with an IList<SomeObject> but only with IList<string>, any idea why? The index column is always null.
You cannot use this style of mapping to map a list of objects. There are other ways to do it.
0

Would be helpful to see the error you get, but one thing seems to be obvious: you are missing setter of the IList<string> CsvExportList. So, mapping should target the field

HasMany<string>(Reveal.Property<string>("_csvExportList"))

Check these how to handle field mapping:

Or change your IList<string> to have at least protected setter (I personally would go this way) and remove the readonly setting.

private IList<string> _csvExportList;
public virtual IList<string> CsvExportList
{
    get { return _csvExportList ?? (_csvExportList = new List<string>(); }
    protected set { _csvExportList = value; }
}

These are hints, the exception or error you get could tell us more

2 Comments

Added additional error message. HasMany<string>(Reveal.Property<string>("_csvExportList")) couldn't be used since the syntax results in error. Also, couldn't have a setter since, readonly fields cannot have setter. I use Add() and AddRange() methods to fill the collection.
Honestly... I did not see the readonly. Why is it there? This does not make sense to me, it only brings you issues. If you want to hide the CsvExportList to any upper layer, hide its setter (make it protected). That's enough. And the error you get is related to fact, that you are working with the entity ExportTask once the session is closed. You have to extend the lifetime of that session or eagerly load that collection... BUT I would go with protected setter for sure...

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.