Какова лучшая практика для списков только для чтения в 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. Эта дискуссия очень помогла мне сформировать тот, который подходит нашему проекту.
Есть подход, который я начал использовать:
- Вспомогательные поля используются для хранения коллекций
- IEnumerable
используется для предоставления коллекций, чтобы заставить клиентов использовать методы AddLine() и RemoveLine(). - Тип 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; }
}