Какова лучшая практика для списков только для чтения в NHibernate

Модель предметной области, над которой я работаю, имеет корневую совокупность и дочерние объекты. Что-то вроде следующего кода:

class Order
{
   IList<OrderLine> Lines {get;set;}
}

class OrderLine
{
}

Теперь я хочу, чтобы мой Орден контролировал линии. Что-то вроде того:

class Order
{
   OrderLine[] Lines {get;}

   void AddLine(OrderLine line);
}

В настоящее время мы используем следующую схему:

class Order
{
   private IList<OrderLine> lines = new List<OrderLine>();
   OrderLine[] Lines {get {return this.lines;}}

   void AddLine(OrderLine line)
   {
      this.orders.Add(line);
   {
}

NHibernate сопоставляется непосредственно с полем линий.

Теперь вопросы...

  • Что вы практикуете в таких ситуациях?
  • Кто-нибудь использует методы: public IEnumerable GetLines()
  • Что вы используете в качестве типа возврата для свойства? Может быть ReadOnlyCollection или IEnumerable;
  • Может быть, это не лучшее место, чтобы спросить? Предложите пожалуйста.

Обновление: кажется, IEnumerable выигрывает, однако решение все еще не идеально...

5 ответов

Решение

Шаблон, который я использую:

class Order
{
   private List<OrderLine> lines = new List<OrderLine>();

   IEnumerable<OrderLine> Lines { get { return this.lines; } }

   void AddLine(OrderLine line)
   {
       this.orders.Add(line);
   }
}

Если вы используете NET 3.5, вы получаете все функции поиска, которые вы можете захотеть для IEnumerable, используя LINQ, и вы скрываете реализацию своей коллекции.

Проблема с возвратом OrderLine[] заключается в том, что ваша коллекция может быть изменена извне, например:

Order.Lines[0] = new OrderLine().

Я делаю это так:

public class Order
{
      private ISet<OrderLine> _orderLines = new HashedSet<OrderLine>();

      public ReadOnlyCollection<OrderLine> OrderLines
      {
          get { return new List<OrderLine>(_orderLines).AsReadOnly(); }
      }

      public void AddOrderLine( OrderLine ol )
      {
          ...
      }
}

Затем, вне зависимости, в отображении NHibernate велит использовать поле _orderLines:

<set name="OrderLine" access="field.camelcase-underscore" ... >
...
</set>

Я представляю коллекции как ReadOnlyCollection и использую методы AddX и RemoveX для поддержки коллекций. Мы только что перешли на 3.5, и вместо этого я собираюсь разоблачить IEnumerable. В большинстве случаев с NHibernate дочерний элемент имеет ссылку на родителя, поэтому предоставление методов Add и Remove позволяет поддерживать эти отношения:

    public void AddPlayer(Player player)
    {
        player.Company = this;
        this._Players.Add(player);
    }

    public void RemovePlayer(Player player)
    {
        player.Company = null;
        this._Players.Remove(player);
    }

Если я выставляю список, который не должен быть изменен, тогда я использую IEnumerable и yield. Я нахожу это громоздким, пытаясь использовать ReadOnlyCollections в сочетании с NHiberante.

При таком подходе у вас все еще есть поле приватных линий, которое отображается и заполняется через NHibernate; однако публичный доступ к коллекции осуществляется через итераторы. Вы не можете добавлять или удалять из базового списка с помощью этого свойства Lines.

Например:

public IEnumerable<OrderLine> Lines {
    get {
        foreach (OrderLine aline in lines) {
            yield return aline;
        }
    }
}

Я провел несколько дней в поисках лучшего подхода для списков только для чтения в NHibernate. Эта дискуссия очень помогла мне сформировать тот, который подходит нашему проекту.

Есть подход, который я начал использовать:

  1. Вспомогательные поля используются для хранения коллекций
  2. IEnumerable используется для предоставления коллекций, чтобы заставить клиентов использовать методы AddLine() и RemoveLine().
  3. Тип ReadOnlyCollection используется в дополнение к IEnumerable.

Код:

public class Order
{
    private readonly IList<OrderLine> lines = new List<OrderLine>();

    public virtual IEnumerable<OrderLine> Lines
    {
        get
        {
            return new ReadOnlyCollection<OrderLine>(lines);
        }
    }

    public void AddLine(OrderLine line)
    {
        if (!lines.Contains(line))
        {
            this.lines.Add(line);
            line.Order = this;
        }
    }

    public void RemoveLine(OrderLine line)
    {
        if (lines.Contains(line))
        {
            this.lines.Remove(line);
            line.Order = null;
        }
    }
}

public class OrderLine
{
    public Order Order { get; set; }
}
Другие вопросы по тегам