Fluent NHibernate - mapping a foreign key as a property

I am looking for a way to add a relationship between two objects and have a custom identifier for a foreign key. I have looked through previous posts, but the closest I can find is a suggestion. Charge the association - and that's not what I hope for. I know that this can be done in the Entity Framework with a .HasForeignKey binding, but I cannot find a way to do this in Fluent NHibernate.

Take two sample objects:

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 create a new Ticket instance and assign the Service to it using the following tools (suppose that the associated Service already exists in the table):

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

What I do not want to do is the following:

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

I have good reasons for this, and as I said, it can be done in the Entity Framework, but I am very fixated on how to achieve the same level 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 is always appreciated!


Just quick editing for Jay is the reason I don't want to use Session.Load because I don't want my view level (MVC 3) to know anything about NHibernate - so I use the repository template and injecting one repository into the controller . So, for example, I will have a TicketRepository that 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 do not want to enter a ServiceRepository also to get a link to a Service for Ticket .. p>

+6
source share
2 answers

As I can see, you cannot avoid using Session.Load (id) when using NHibernate. As mentioned in the comments, this will NOT get into the database, just create a proxy object with an identifier.

Some possible options:

  • Deploy a second shared repository (ServiceRepository) to the controller. I don't see this as a problem, but for some reason you want to avoid this. You can add the LoadById method to the universal interface and implement it differently in each implementation for NH and EF (or others). In EF impl, this method can work just like GetById, while in NH impl it calls Session.Load
  • Deploy a non-shared repository for AR (root placeholder), which in this case will be Ticket. This may have special methods for downloading the service as well as for the ticket.
  • Make another abstraction on top of the two repositories and add it to the controller instead of the two repositories in option 1. This can be f.ex be immune to UnitOfWork integrity, as described here: Persistance ignorant UoW or some kind of application that organizes ticket creation or TicketFactory .

Of the 3 options, option 1 is probably the easiest, while 3 can provide better abstraction and greater maintainability along the way.

+3
source

You can use the trick. To keep your code clean.

As with NH, you must implement this solution in NH Repositories, so I allow it this way.

before adding or updating

 if (!string.IsNullOrEmpty(ServiceId) && Service == null) { Service = new Service{ Id = ServiceId }; } 

normal operation of the repository ...

I test and work. Your architecture is still stripped of ORM solutions.

0
source

Source: https://habr.com/ru/post/922845/


All Articles