Developer-safe bi-directional relationships with NHibernate
I know how to map bi-directional relationships with NHibernate, but does anyone know an effective technique to make them 'developer safe'.
What I mean by that, 开发者_如何转开发is that as soon as one end of the relationship is established, the other end should also be set, for example:
[Test]
public void TestBidirectionalRelationships_WhenAddingOptionToProduct()
{
var product = new Product();
var productOption = new ProductOption();
product.AddOption(productOption);
Assert.That(product.Options.Contains(productOption));
Assert.That(productOption.Product, Is.EqualTo(product);
}
[Test]
public void TestBidirectionalRelationships_WhenSettingProductOnOption()
{
/* Alternatively, productOption.Product would have no public setter */
var product = new Product();
var productOption = new ProductOption();
productOption.Product = product;
Assert.That(product.Options.Contains(productOption));
Assert.That(productOption.Product, Is.EqualTo(product);
}
How would one achieve this, without making the code horrendously complex, and whilst also keeping NHibernate happy?
One side:
class Product
{
public Product()
{
_Options = new List<ProductOption>();
}
ICollection<ProductOption> _Options;
public virtual IEnumerable<ProductOption> ProductOptions
{
get { return _Options.Select(x => x); }
}
public virtual AddOption(ProductOption option)
{
option.Product = this;
}
protected internal virtual AddOptionInternal(ProductOption option)
{
_Options.Add(option);
}
}
Many side:
class ProductOption
{
Product _Product;
public virtual Product Product
{
get { return _Product; }
set
{
_Product = value;
_Product.AddOptionInternal(this);
}
}
}
Mapping:
<class name="Product">
...
<bag name="Options" access="field.pascalcase-underscore">
...
<class name="ProductOption">
...
<many-to-one name="Product" access="field.pascalcase-underscore"/>
Removal of options from the collection (from either side) is left as an exercise :-)
Diego's solution is fine but I prefer this pattern:
One side:
public class Product
{
private IList<ProductOption> _options;
public Product()
{
_options = new List<ProductOption>();
}
public virtual IEnumerable<ProductOption> ProductOptions
{
get { return _options; }
}
public virtual AddOption(ProductOption option)
{
// equality must be overridden for this to work
// Check contains to break out of endless loop
if (!_options.Contains(options))
{
_options.Add(option);
option.Product = this;
}
}
}
Many side:
public class ProductOption
{
Product _product;
public virtual Product Product
{
get { return _product; }
set
{
_product = value;
_product.AddOption(this);
}
}
}
Have a look at this article which specifically addresses this issue. The guidance here is very valuable for keeping such relationships clean by encapsulating the collection operations within your domain model.
加载中,请稍侯......
精彩评论