It is pretty common, especially in applications with an ORM, to have a two way mapping between classes. Like this:
public class Product
{
private List
My first thought is, in your function/property used to add prices, add a line of code like so:
public void addPrice(Price p) {
//code to add price goes here
p.Product = this;
}
In the past, I've done something like this when I needed to maintain this type of relationship...
public class Owner
{
public List<Owned> OwnedList { get; set; }
}
public class Owned
{
private Owner _owner;
public Owner ParentOwner
{
get
{
if ( _owner == null )
_owner = GetParentOwner(); // GetParentOwner() can be any method for getting the parent object
return _owner;
}
}
}
In the past I've added "link" methods, i.e., instead of "setting" the Price on a Product, you link the product and the price.
public void linkPrice(Price toLink) {
this.price = toLink;
toLink.setProduct(this);
}
(if you use setPrice to do this, then setProduct would also do this, and they would forever call each other in the second line, hence I create an explicit link method instead of using the setters and getters. Indeed the setter could be package protected.
YMMV, your situation could be different.
First, I think the example your present is confusing - it's uncommon for something like a Price to be modeled as an object or to have reference to the entities that would have a price. But I think the question is legitimate - in the ORM world this is sometimes referred to as graph consistency. To my knowledge there isn't one definitive way to tackle this problem, there are several ways.
Let's start by changing the example slightly:
public class Product
{
private Manufacturer Manufacturer { get; private set; }
}
public class Manufacturer
{
private List<Product> Products { get; set; }
}
So every Product has one Manufacturer, and each Manufacturer could have a list of products. The challenge with the model is that if the Product class and Manufacturer class maintain disconnected references to one another, updating one can invalidate the other.
There are several ways to address this issue:
Eliminate the circular reference. This solves the problem but makes the object model less expressive and harder to use.
Change the code so that the Manufacturer reference in Product and Products list in Manufacturer are reflexive. In other words, changing one affects the other. This generally requires some code the setter and the collection to intercept changes and reflect them into one another.
Manage one property in terms of the other. So, rather than storing a reference to a manufacturer within Product, you compute it by search through all Manufacturers until you find the one that owns you. Conversely, you could keep a reference to the Manufacturer in the Product class and build the list of Products dynamically. In this approach, you would generally make one side of the relationship read-only. This, by the way, is the standard relational database approach - entities refer to each other through a foreign key which is managed in one place.
Externalize the relationship from both classes and manage it in a separate object (often called a data context in ORM). When Product wants to return its manufacturer it asks the DataContext. When the Manufacturer want to return a list of Products it does the same. Internally, there are many ways to implement a data context, a set of bi-directional dictionaries is not uncommon.
Finally, I will mention, that you should consider using an ORM tool (like NHibernate or CSLA) that can help you manage graph consistency. This is generally not an easy problem to solve correctly - and it can easily become very complicated once you start exploring cases like many-to-many relationships, one-to-one relationships, and lazy loading of objects. You are better of using an existing library or product, rather than inventing a mechanism of your own.
Here are some links that talk about bidirectional associations in NHibernate that you may find useful.
Here's a code example of managing the relationships directly yourself using method #2 - which is typically the simplest. Note that only one side of the relationship is editable (in this case, the Manufacturer) - external consumers cannot directly set the Manufacturer of a Product.
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;
}
}
I am just now working on a problem similar to this and I am using #3 in LBushkin's answer.
I have a data storage object with lists for all of my data classes. The data classes have ids in them for references to the other classes and I call back to the data storage class to get the reference item.
I have found this really useful because I need to be able to filter the data and that is done when requesting the data from the data storage.
This is not the correct way to model this problem.
A Product
ought to have a Price
, a Price
ought not to have a Product
:
public class Product
{
public Price CurrentPrice {get; private set; }
public IList<Price> HistoricPrices { get; private set;}
}
public class Price { }
In your particular setup, what does it mean to for a Price
to have a Product
? In the class I created above you would be able to handle all pricing within the Product
class itself.