views:

2078

answers:

3

Any using nHibernate with a Domain object & DTO object implemented from a common interface? I'm trying to separate all of my nHibernate attributes into the Domain object, leaving my DTO's and interface clean.

The problem comes with nHibernate throwing errors when it tries to associate the interfaces with the concrete classes.

NHibernate.MappingException: Association references unmapped class: IContact

I understand why its complaining about the use of the non-hibernated interface, but I'm struggling to visual a way to restructure around it. A skeleton reproduction of my code is set out as below, any ideas for how to structure my code better?

public interface ICompany
{
    IList<IContact> Contacts { get; set; }
}

public class CompanyDTO : ICompany
{
    private IList<IContact> contacts;
    public IList<IContact> Contacts { get { return this.contacts; } set { this.contacts = value; } }

}

[ActiveRecord]
public class Company : ActiveRecordBase<Company>, ICompany
{
    private IList<IContact> contacts;
    [HasMany(Inverse=true, Table="Contact", ColumnKey="CompanyId")] 
    [ScriptIgnore]
    public IList<IContact> Contacts { get { return this.contacts; } set { this.contacts = value; } }
}

Edit:

I want to have a common interface so that I can ensure they are keeping the same fields (ie. leaning on the compiler to keep them consistent). It also allows me to use the DTO's in the view part of my application, but casts them to domain objects for business and data access. Also, alex's solution does not work because ICompany's Contacts is of type IList, not IList. I would like to keep it as IContact so my DTO object has no knowledge of the Contact Domain object.

A: 

Well in your domain you can't use the IContract to reference to your domain entity use Concrete class instead. If you want to correct your version use simply this:

[ActiveRecord]
public class Company : ActiveRecordBase<Company>
{
    private IList<Contact> contacts;
    [HasMany(Inverse=true, Table="Contact", ColumnKey="CompanyId")] 
    [ScriptIgnore]
    public IList<Contact> Contacts { get { return this.contacts; } set { this.contacts = value; } }
}

I don't see the point to interface your domain and your DTOs. They are coupled, and they can have not the same informations. For example you could keep some information very weel encapsulated into your Domain and only communicate few other informations. DTO are made to transfert the data you want to share with up-layers.

You can have Base class to define your entity and your ValueObject. In brief Entity : DomainEntity are ID able means they can be persisted. ValueObject = DTO cannot be persisted (not ID able)

Look at the core design of Sharp-Arch:

  • /BaseObject.cs: Provides basic object comparative services.
  • /Entity.cs: Provides an object with a domain signature and a typeable ID property. This also has the validation support of NHibernate Validator. Objects which extend from Entity MUST have at least one [DomainSignature] property; it'll throw a Design-By-Contract exception if this is violated. The interface IEntityWithTypedID allows you to roll your own.
  • /ValueObject.cs: This is a value object wherein all of its properties are used when compared to another value object. Objects which extend from ValueObject may not have any [DomainSignature] properties; it'll throw a Design-By-Contract exception if this is violated.
alexl
I want to have a common interface so that I can ensure they are keeping the same fields (ie. leaning on the compiler to keep them consistent). It also allows me to use the DTO's in the view part of my application, but casts them to domain objects for business and data access
jacko
Also, your solution does not work because ICompany's Contacts is of type IList<IContact>, not IList<Contact>. I would like to keep it as IContact so my DTO object has no knowledge of the Contact Domain object.
jacko
sorry made the change removing the interface implementation
alexl
You can't cast ContactDto to Contact directly you still need to use conversion. You can cast ContactDto to IContact but not to Contact
alexl
+2  A: 

In your concrete case you should just add Type = typeof(Contact) to the mapping attribute, like so:

[HasMany(Inverse=true, Table="Contact", ColumnKey="CompanyId", Type=typeof(Contact))]
mookid8000
Hej, do you know how to do that with Fluent too? :)
asgerhallas
A: 

And what shall i do if i have [HasMany] attribute? It actually hasn't property name 'Type', but [Property] and [BelongsTo] ones have.

UPDATE The answer is to use 'CollectionType = typeof(YourType)'

UPDATE 2 No, It doesn't working, this property is set for collection type i.e. List etc. Trying to set [HasMany(typeof(meType), ...)] but still not works.