6

Estoy buscando una manera de agregar una asociación entre dos entidades y tener un ID configurable para la clave externa. He buscado en publicaciones anteriores, pero lo más cercano que puedo encontrar es una sugerencia para cargar la asociación, que no es lo que estoy esperando. Sé que esto se puede hacer en Entity Framework con el enlace .HasForeignKey, pero parece que no puedo encontrar una manera de hacerlo en Fluent NHibernate.Fluidez NHibernate - mapeo de una clave foránea como propiedad

tomar las entidades dos ejemplos:

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; } 
} 

Quiero ser capaz de crear una nueva instancia de entradas y asignar un servicioa él utilizando los siguientes medios (suponer que el servicio asociado ya existe en la tabla):

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

lo que no quiero hacer es la siguiente:

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

tengo razones válidas para esto, y como he dicho esto se puede hacer en el marco de la entidad, pero realmente estoy perplejo en cuanto a cómo lograr lo mismo en Fluido NHibernate. Mis asignaciones actualmente se ven así:

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"); 
    } 
} 

Cualquier ayuda siempre se agradeció!


Sólo una edición rápida para Jay - la razón por la que no quiero Session.load mi elemento es porque yo no quiero que mi capa de presentación (MVC 3) saber nada de NHibernate - Por lo tanto, Estoy usando un patrón de repositorio e inyectando un único repositorio en el controlador. Así, por ejemplo, voy a tener un TicketRepository que se adhiere a la siguiente contrato

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

yo no quiero tener que inyectar una ServiceRepository también sólo para obtener una referencia al servicio deel Ticket.

+1

¿Puede explicar los motivos válidos para no querer utilizar 'Session.Load'? – Jay

+1

@Jay, no estoy seguro de la razón de Terric ... pero a veces puede ser ridículo sobrecargar un objeto solo para poder hacer referencia a la clave que ya tiene antes de guardar, en mi humilde opinión. Teníamos un acuerdo de nivel de servicio estricto en un proyecto anterior en el que tuvimos que hacer el mismo trabajo en Entity Framework antes de que tuviera soporte de FK. –

+0

@Jay he actualizado mi publicación con motivos. Además, Kevin hace un buen punto, no quiero la sobrecarga adicional de cargar otra entidad para esto asociado. –

Respuesta

3

De la forma en que lo veo, no se puede evitar el uso de Session.Load (id) cuando se usa NHibernate. Como se mencionó en los comentarios, esto NO afectará la base de datos, solo crea un objeto proxy con la ID.

Algunas posibles opciones:

  1. inyectar un segundo repositorio genérico (ServiceRepository) en el controlador. Realmente no puedo ver un problema con eso, pero por alguna razón quieres evitarlo. Puede agregar un método LoadById a la interfaz genérica e implementarlo de manera diferente en cada implementación para NH y EF (u otros). En EF impl ese método puede funcionar igual que GetById, mientras que en NH impl llama a Session.Load
  2. Implemente un repositorio no genérico para el AR (raíz agregada) que en este caso sería Ticket. Esto podría tener métodos específicos para Cargar un servicio además de Ticket.
  3. Implemente otra abstracción en la parte superior de los dos repositorios e inyecte eso en el controlador en lugar de los dos repositorios en la opción 1. Esto podría f.ex ser una persistencia ignorante UnitOfWork como se describe aquí: Persistance ignorant UoW, o algún tipo de Servicio de Aplicación que orquesta la creación de Tickets, o una TicketFactory.

De las 3 opciones, la opción 1 es probablemente la más simple, mientras que 3 podrían proporcionar una mejor abstracción y más capacidad de mantenimiento en el camino.

+0

Gracias, tener una mejor comprensión de 'Session.Load' significó que ya no me preocupa usarlo. Terminé usando el framework de entidad en su lugar y dejé NHibernate (principalmente porque estoy más cómodo con EF pero quería ver lo que NH tenía para ofrecer). –

+0

He estado considerando la idea de convertir mis claves foráneas en enteros en lugar de objetos porque no quería tener que golpear el DB para cada objeto vinculado en cada inserción o actualización ... hasta que me encontré con esta pregunta y aprendí sobre Session.Load(). Después de comparar los resultados del registro nhibernate uno al lado del otro para operaciones simples, ¡guau! ¡GRANDES ahorros! ¡Gracias! – Brett

0

Puede usar un truco. Para mantener tu código limpio.

Como este es un problema de NH, debe implementarlo solución en los repositorios de NH así que lo resuelvo así.

antes de añadir o actualizar

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

trabajo repositorio de lo normal ...

lo prueba y el trabajo. Su arquitectura aún está limpia de decisiones ORM

+0

supongamos que si la clase de servicio tiene varios campos, en ese caso, ¿tenemos que asignar todos los campos aquí? ya que estoy enfrentando el mismo problema ... – jkyadav

Cuestiones relacionadas