Exposing HasMany and ManyToMany relationships as IEnumerable - nhibernate

Currently in my entities I'm exposing my collections as an IList but I've been thinking about exposing them as a IEnumerable to prevent users from manually adding to the collections. I have specific adds for these operations so that I can make sure my bi-directional relationships stay intact. A couple questions come to mind in this scenario.
If I expose them as IEnumberable does this mean I'll need an Add and Remove method for every collection that represents a relationship in my entities?
Is there an easier way to do this? I'm not against doing it this way just wondering.
Are you doing it this way?
Example:
public class OrderHeader
{
public virtual Guid OrderId { get; private set; }
public virtual IList<OrderLine> OrderLines { get; set; }
public virtual void AddLine(OrderLine orderLine)
{
orderLine.Order = this;
OrderLines.Add(orderLine);
}
//No need for a remove method since we expose collection as IList
}
Converting the class above so that we only expose IEnumerable would result in:
public class OrderHeader
{
public virtual Guid OrderId { get; private set; }
private IList<OrderLine> orderLines { get; set; }
public IEnumerable<OrderLine> OrderLines { get { return orderLines; } }
public virtual void AddLine(OrderLine orderLine)
{
orderLine.Order = this;
orderLines.Add(orderLine);
}
public virtual void RemoveLine(OrderLine orderLine)
{
orderLines.Remove(orderLine);
}
}

Yes, if you expose an IEnumerable it is best to add methods on the class to handle Add/Remove
A private backing field is a pretty good solution.
Yes, but keep in mind if you want truly read only access to the exposed collection use ReadOnlyCollection - http://msdn.microsoft.com/en-us/library/ms132474.aspx

Agreed with Dan's answer, with a minor change:
public IEnumerable<OrderLine> OrderLines
{ get { return orderLines.Select(x => x; } }

Related

Automapper and NHibernate lazy loading

I am struggling with this issue:
I have a list of NHibernate objects called "Project". These objects contain a lazy - loaded list of "Branches". I am trying to pass a list of Projects to a WCF service so I am using AutoMapper to transform them to flat objects.
The problem is that even though the destination objects called "ProjectContract" does not contain a list of Branches, Automapper still invokes this collection and a lot of queries are made to the database because NHibernate fires the lazy - loading and loads the Branches collection for each project.
Here are the classes and the mapping:
public class Project
{
public virtual int ID
{
get;
set;
}
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual IList<Branch> Branches { get; set; }
}
[DataContract]
public class ProjectContract
{
[DataMember]
public virtual int ID
{
get;
set;
}
[DataMember]
public virtual string Name { get; set; }
[DataMember]
public virtual string Description { get; set; }
}
public class ProjectMappings : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Project, ProjectContract>();
}
}
My question is: Is there a way to tell AutoMapper to not touch the "Branches" collection because I don't care about it and that is a proxy that will trigger many database calls?
I temporarily fixed this with MaxDepth(0), but there are other entities where I have collections that I want to transfer, and collections that I don't want to be touched, like this one. In that case, MaxDepth(0) will not work.
Thank you,
Cosmin
Yes, The AutoMapper Ignore function.
Mapper.CreateMap<Source, Destination>()
.ForMember(dest => dest.SomeValuefff, opt => opt.Ignore());

Why HashedSet forces loading lazy collection?

I query items with lazy collections in via nHibernate. Items are queried without fetching collections. But when i try to create HashedSet
var hashedSet = new HashedSet<Thing>(Session.Query<Thing>())
from those items all lazy stuff is fetched. Whats causing that?
[Serializable]
public class Thing {
public virtual String Name { get; set; }
public Thing() {
OtherThings = new HashedSet<OtherThing>();
}
public virtual ISet<OtherThing> OtherThings { get; set; }
}
Maybe you have overridden GetHashCode() in the entity (or any base class of it) and access the properties there?

Is the properties in Entity must be virtual when using FluentNhibernate?

Which entity FluentNHibernate uses as entity
I create some entity in Domain(or BLL), such as the following:
public class Role
{
public long ID { get; protected set; }
public string Name { get; set; }
public string Description { get; set; }
public List<User> Users { get; set; }
public Role()
{
Users = new List<User>();
}
}
And I want make use of FlunetNHibernate to map them, but get errors:
The following types may not be used as proxies:
Freeflying.Domain.Core.Profile: method get_ID should be 'public/protected virtual' or 'protected internal virtual'
Yes, I recall the programmer requirement when use FluentNHibernate, the entity should be like this:
public class Role
{
public virtual long ID { get; protected set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
But It looks wired. Do you think so? How do you do when using FluentNHibernate? I don't want go back to Domain layer and add virtual for every property.
This is a basic requirement for using NHibernate; It allows NHibernate to generate a proxy class that descends from your class for lazy loading and such.
I have not seen a method of removing this requirement, though if such a thing is possible it would mean that you could not use lazy loading of objects and/or properties.
Here's a blog post that explains this a bit more; It also offers a way to avoid marking your properties as virtual, although I would really recommend that you do not use this method (marking classes to avoid lazy loading) as the benefits of lazy loading in most circumstances far outweigh the cost of making your properties virtual.

Fluent NHibernate with ManyToMany and Custom Link Table

I have the following schema, and when I delete one of the objects on one many side, it seems to be trying to delete the objects on the other many side. Am somewhat confused about the proper Cascade options to use, and I don't find Oren's brief description of them to be useful, so please don't quote those back.
public class Store {
public virtual IList<StoreProduct> StoreProducts { get; set; }
}
public class Product {
public virtual IList<StoreProduct> StoreProducts { get; set; }
}
public class StoreProduct {
public virtual Store Store { get; set; }
public virtual Product Product { get; set; }
public virtual Decimal Cost { get; set; } //this is why I have a custom linking class
}
In my mapping overrides, I have:
For Store:
mapping.HasMany(x => x.StoreProducts).Cascade.AllDeleteOrphan().Inverse;
For Product:
mapping.HasMany(x => x.StoreProducts).Cascade.AllDeleteOrphan().Inverse;
When I try to delete a Store that has associated StoreProducts, it seems that NHIbernate tries to delete not only the StoreProducts, but the Products.
Here are my conventions:
return c =>
{
c.Add<ForeignKeyConvention>();
c.Add<HasManyConvention>();
c.Add<HasManyToManyConvention>();
c.Add<ManyToManyTableNameConvention>();
c.Add<PrimaryKeyConvention>();
c.Add<ReferenceConvention>();
c.Add<EnumConvention>();
c.Add<TableNameConvention>();
c.Add<CascadeAll>();
c.Add(DefaultCascade.All());
};
HasManyConvention:
public void Apply(IOneToManyCollectionInstance instance)
{
instance.Key.Column(instance.EntityType.Name + "Fk");
instance.Cascade.AllDeleteOrphan();
instance.Inverse();
}
What am I doing wrong?
Thanks!
p.s.: I don't want to overwhelm people w/code, but can post more if needed.
Thanks, CrazyDart - I think that is among the things I tried without success. What I ended up doing was adding a StoreProducts override that looks like this:
public class StoreProductOverride: IAutoMappingOverride<StoreProduct>
{
#region IAutoMappingOverride<StoreProduct> Members
public void Override(AutoMapping<IndicatorStrategy> mapping)
{
mapping.References(x => x.Store).ForeignKey("StoreFk").Cascade.SaveUpdate();
mapping.References(x => x.Producty).ForeignKey("ProductFk").Cascade.SaveUpdate();
}
#endregion
}
Seems to work, but QA hasn't tried to break it yet (-:
You need to turn off the cascading on StoreProduct is my guess. Its hard to test without setting it up. I see the cascade on Store and Product, but turn it off on StoreProduct.

Nhibernate - Initialize lists - Best Practice?

I was just wondering about some CodeWarning (ConstructorsShouldNotCallBaseClassVirtualMethods), and if there is a better way to do it. I have a simple log collector class, and I am using NHibernate to retrieve some of the objects.
Some times I create objects by myself (of course) and add them to NHibernate for persistance. What is the best way to make sure that Lists are never NULL.
Currently I am doing this, but it does not seems "perfect". Any idea on this topic?
public class LogRun
{
public virtual int Id { get; private set; }
public virtual DateTime StartTime { get; set; }
public virtual DateTime EndTime { get; set; }
public virtual IList<Log> LogMessages { get; set; }
public virtual int LogMessageCount { get { return LogMessages.Count; } }
public LogRun()
{
LogMessages = new List<Log>();
}
}
Is LogMessages a persisted thing? If so, it's best practice to never expose a public setter. NHibernate gets weird if you retreive from the database and then replace that IList with a new one:
var myLog = session.Get<LogRun>(1);
Assert.True(myLog.LogMessages.Count > 0);
myLog.LogMessages = new List<Log>();
If you note, NHibernate is returning a proxied object and replacing it with a generic list will cause it to go wonky when you try and save back.
As a rule, I prefer to have a private field that I initialize and then expose only a getter to the client:
public class LogRun
{
private IList<Log> logMessages = new List<Log>();
public virtual int Id { get; private set; }
public virtual DateTime StartTime { get; set; }
public virtual DateTime EndTime { get; set; }
public virtual IList<Log> LogMessages { get { return logMessages; } }
public virtual int LogMessageCount { get { return LogMessages.Count; } }
public void AddLogMessage(Log log)
{
logMessages.Add(log);
}
}
Actually, I go a step further, the client gets an IEnumerable<> and I add a helper function for the add.
My implmentation would look like
public class LogRun
{
private IList<Log> logMessages = new List<Log>();
public virtual int Id { get; private set; }
public virtual DateTime StartTime { get; set; }
public virtual DateTime EndTime { get; set; }
public virtual IEnumerable<Log> LogMessages { get { return logMessages; } }
public virtual int LogMessageCount { get { return LogMessages.Count(); } }
public void AddLogMessage(Log log)
{
logMessages.Add(log);
}
}
I do the same thing, but I also wonder how big the perfomance impact is, since NHibernate will also create a new List<> for every default constructor call..
I think we're in luck though, and that it will work. Consider NHibernate creating a lazy-loaded list of LogRun's (which is why we mark everything as virtual anyway):
NHibernate will reflect over LogRun and create a derived class
NHibernate will make a proxy-list of the LogRun-derived class
--
When you load that proxy, it will instantiate some of those derived classes, however, the base-constructor is called first - creating the new list<> - then the derived constructor is called, creating a proxy-list instead.
Effectively, we have created a list that we will never use.
Consider the alternatives though:
Make the constructor protected, so that no one will call it, and make an alternative. For example, a static LogRun.GetNew(); method.
Allow public set-access to the IList<> and create it yourself whenever you create a new object.
Honestly, I think both are very messy, and since I'm (pretty) sure that the perfomance overhead on creating a new empty list on each constructor-call is limited, that's what I'm personally sticking too so far.. Well, at least untill my profiler tells me otherwise :P