Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fluent NHibernate - mapping a foreign key as a property

I'm looking for a way of adding an association between two entities and having a settable Id for the foreign key. I have searched through previous posts, but the closest I can find is a suggestion to .Load the association - which isn't what I'm hoping for. I know this can be done in Entity Framework with the .HasForeignKey binding, but I can't seem to find a way to do it in Fluent NHibernate.

Take the two example entities:

public class Ticket
{
    public virtual int Id { get; set; }
    public virtual string Title { get; set; }
    public virtual string ServiceId { get; set; }
    public virtual Service Service { get; set; }
}

public class Service
{
    public virtual string Id { get; set; }
}

I want to be able to create a new instance of Ticket and assign a Service to it using the following means (assume that the associated Service already exists in the table):

Ticket ticket = new Ticket() {
    Title = "Problem with MS Word",
    ServiceId = "Microsoft Word 2012"
};

What I don't want to do is the following:

Ticket ticket = new Ticket() {
    Title = "Problem with MS Word",
    Service = Session.Load<Service>("Microsoft Word 2012")
};

I do have valid reasons for this, and like I've said this can be done in Entity Framework, but I'm really stumped as to how to achieve the same thing in Fluent NHibernate. My mappings currently look like this:

public class TicketMapping : ClassMap<Ticket>
{
    public TicketMapping()
    {
        Id(m => m.Id);
        Map(m => m.Title).Column("Title");
        Map(m => m.ServiceId).Column("ServiceId");
        HasOne(m => m.Service).ForeignKey("ServiceId");

        Schema("dbo");
        Table("Tickets");
    }
}

public class ServiceMapping : ClassMap<Service>
{
    public ServiceMapping()
    {
        Id(m => m.Id);

        Schema("dbo");
        Table("Services");
    }
}

Any help always appreciated!


Just a quick edit for Jay - the reason I don't want to Session.Load my element is because I don't want my presentation layer (MVC 3) knowing anything about NHibernate - therefore I'm using a repository pattern and injecting a single repository into the controller. So for example, I'll have a TicketRepository which adheres to the following contract

public interface IRepository<T>
{
    T GetById(object id);
    void Create(T entity);
    void Update(T entity);
    void Delete(T entity);
}

I don't want to have to inject a ServiceRepository also just to get a reference to the Service for the Ticket.

like image 964
Paul Aldred-Bann Avatar asked Aug 14 '12 15:08

Paul Aldred-Bann


1 Answers

The way I see it you can't really avoid using Session.Load(id) when using NHibernate. As mentioned in the comments this will NOT hit the database, just create a proxy object with the id.

Some possible options:

  1. Inject a second generic repository (ServiceRepository) into the controller. I can't really see an issue with that, but for some reason you want to avoid it. You could add a LoadById method to the generic interface and implement that differently in each implementation for NH and EF (or others). In EF impl that method may work just like GetById, while in NH impl it calls Session.Load
  2. Implement a non-generic repository for the AR (aggregate root) which in this case would be Ticket. This could have specific methods to Load a Service as well as Ticket.
  3. Implement another abstraction on top of the two repositories and inject that into the controller instead of the two repositories in option 1. This could f.ex be a persistance ignorant UnitOfWork as outlined here: Persistance ignorant UoW, or some kind of Application Service that orchestrates the creation of Tickets, or a TicketFactory.

Of the 3 options, option 1 is probably the simplest, while 3 might provide better abstraction and more maintainability down the road.

like image 105
Trygve Avatar answered Nov 07 '22 10:11

Trygve