Ответ 1
Во-первых, я думаю, что пример, который ваш подарок сбивает с толку, - это редкость, когда что-то вроде цены моделируется как объект или имеет ссылку на сущности, которые будут иметь цену. Но я думаю, что вопрос правомерен - в мире ORM это иногда называют согласованностью графиков. Насколько мне известно, не существует однозначного способа решения этой проблемы, есть несколько способов.
Давайте начнем с небольшого изменения примера:
public class Product
{
private Manufacturer Manufacturer { get; private set; }
}
public class Manufacturer
{
private List<Product> Products { get; set; }
}
Таким образом, у каждого товара есть один производитель, и у каждого производителя может быть список товаров. Проблема с моделью заключается в том, что если класс Product и класс Manufacturer сохраняют несвязанные ссылки друг на друга, обновление одного может сделать недействительным другой.
Есть несколько способов решения этой проблемы:
-
Устранить круговую ссылку. Это решает проблему, но делает объектную модель менее выразительной и более сложной для использования.
-
Измените код таким образом, чтобы ссылка на производителя в списке "Продукция и продукты" в разделе "Производитель" была рефлексивной. Другими словами, изменение одного влияет на другое. Обычно для этого требуется некоторый код, который устанавливает и собирает коллекция, чтобы перехватывать изменения и отражать их друг в друге.
-
Управляйте одним свойством с точки зрения другого. Таким образом, вместо того, чтобы хранить ссылку на производителя в Product, вы вычисляете ее путем поиска по всем производителям, пока не найдете того, кто владеет вами. И наоборот, вы можете сохранить ссылку на производителя в классе Product и динамически создавать список продуктов. При таком подходе вы обычно делаете одну сторону отношений доступной только для чтения. Между прочим, это стандартный подход к реляционной базе данных - сущности ссылаются друг на друга через внешний ключ, который управляется в одном месте.
-
Выделите отношения из обоих классов и управляйте ими в отдельном объекте (часто называемом контекстом данных в ORM). Когда Product хочет вернуть своего производителя, он запрашивает DataContext. Когда производитель хочет вернуть список продуктов, он делает то же самое. Внутренне, есть много способов реализовать контекст данных, набор двунаправленных словарей не является редкостью.
Наконец, я упомяну, что вам следует рассмотреть возможность использования инструмента ORM (например, NHibernate или CSLA), который может помочь вам управлять согласованностью графиков. Как правило, эту проблему решить непросто, и она может стать очень сложной, если вы начнете изучать такие случаи, как отношения "многие ко многим", отношения "один к одному" и ленивая загрузка объектов. Вам лучше использовать существующую библиотеку или продукт, а не изобретать собственный механизм.
Вот некоторые ссылки, которые говорят о двунаправленных ассоциациях в NHibernate, которые вы можете найти полезными.
Вот пример кода для непосредственного управления отношениями с помощью метода № 2, который обычно является самым простым. Обратите внимание, что редактируется только одна сторона отношения (в данном случае - Производитель) - внешние потребители не могут напрямую устанавливать производителя продукта.
public class Product
{
private Manufacturer m_manufacturer;
internal Manufacturer Manufacturer
{
get { return m_manufacturer; }
set { m_manufacturer = value; }
}
}
public class Manufacturer
{
private List<Product> m_Products = new List<Product>();
public IEnumerable<Product> Products { get { return m_Products.AsReadOnly(); } }
public void AddProduct( Product p )
{
if( !m_Products.Contains( p ) )
{
m_Products.Add( p );
p.Manufacturer = this;
}
}
public void RemoveProduct( Product p )
{
m_Products.Remove( p );
p.Manufacturer = null;
}
}