Programming to interfaces while mapping with Fluent NHibernate

I have been whipped into submission and have started learning Fluent NHibernate (no previous NHibernate experience). In my project, I am programming to interfaces to reduce coupling etc. That means pretty much "everything" refers to the interface instead of the concrete type (IMessage instead of Message). The thought behind this is to help make it more testable by being able to mock dependencies.

However, (Fluent) NHibernate doesn't love it when I try to map to interfaces instead of concrete classes. The issue is simple - according to the Fluent Wiki, it is smart to define the ID field of my class as for instance

int Id { get; private set; }

to get a typical auto-generated primary key. However, that only works with concrete classes - I can't specify an access level on an interface, where the same line has to be

int Id { get; set; }

and I guess that negates making the setter private in the concrete class (the idea being that only NHibernate should ever set the ID as assigned by the DB).

For now, I guess I will just make the setter public and try to avoid the temptation of writing to it.. But does anyone have an idea of what would be the "proper", best-practice way to create a proper primary-key field that only NHibernate can write to while still only programming to interfaces?

UPDATED

From what I understand after the two answers below from mookid and James Gregory, I may well be on the wrong track - there shouldn't be a reason for me to have an interface per entity as I have now. That's all well and good. I guess my question then becomes - is there no reason to program 100% against an interface for any entities? And if there is even a single situation where this could be justified, is it possible to do this with (Fluent) NHibernate?

I ask because I don't know, not to be critical. Thanks for the responses. :)


UPDATE: using union-subclass is not supported via the fluent interface fluent-nhibernate provides. You'll have to use a regular hbm mapping file and add it.

I too I'm trying do this with fluent NHibernate. I don't think it should be a problem mapping interfaces. You want to use an inheritance strategy, specifically the table-per-concrete-class strategy.

Essentially, you create a mapping definition for the base class (in this case your interface) and specify how to NHibernate should deal with implementers by using union-subclass.

So, for example, this should allow you to make polymorphic associations:

<class name="IAccountManager"
                abstract="true"
                table="IAccountManager">

        <id name="Id">
                <generator class="hilo"/>
        </id>

        <union-subclass
                table="DefaultAccountManager"
                name="DefaultAccountManager">
                <property name="FirstName"/>
        </union-subclass>

        <union-subclass
                table="AnotherAccountManagerImplementation"
                name="AnotherAccountManagerImplementation">
                <property name="FirstName"/>
        </union-subclass>
        ...
</class> 

Note how the Id is the same for all concrete implementers. NHibernate required this. Also, IAccountManager table doesn't actually exist.

You can also try and leverage NHibernate's Implicit Polymorphism (documented below the table-per-concrete-class strategy) - but it has tons of limitations.


I realise this is a diversion, and not an answer to your question (although I think mookid has got that covered).

You should really evaluate whether interfaces on your domain entities are actually providing anything of worth; it's rare to find a situation where you actually need to do this.

For example: How is relying on IMessage any less coupled than relying on Message , when they both (almost) undoubtedly share identical signatures? You shouldn't need to mock an entity, because it's rare that it has enough behavior to require being mocked.


You can adjust your interface to contain only a getter:

public interface ISomeEntity
{
    int Id { get; }
}

Your concrete class can still implement a setter as well, and since you are programming to your interfaces you will never call the setter "by accident".

If you want to disallow setting the id even when you hold a reference to a concrete instance, you can refrain from implementing a setter, and then let NHibernate access the field instead of the property - that's right, NHibernate can use some nifty reflection trickery to set your id field directly instead of invoking the property. Then you might map the id like this:

Id(e => e.Id).Access.AsCamelCaseField();

in which case your Id property must be backed by a corresponding id field. There are more naming conventions, eg if you prefer underscores as private field prefix.

链接地址: http://www.djcxy.com/p/39448.html

上一篇: 流利的NHibernate FluentMappings.AddFromAssemblyOf <>问题

下一篇: 用Fluent NHibernate进行映射时编程接口