Pregunta

Tengo el siguiente mapeo:

<set name="People" lazy="true" table="ProjectPeople">
  <key column="ProjectId" />
  <composite-element class="PersonRole">
    <many-to-one name="Person" column="PersonId" cascade="save-update" not-null="true" />
    <many-to-one name="Role" column="RoleId" cascade="save-update" not-null="true"  />
  </composite-element>
</set>

Ahora, realmente no quiero tener una clase separada para Rol en el dominio, solo necesito el nombre del Rol.Sin embargo, en la base de datos, los roles aún deben normalizarse en una tabla separada. Role (Id, Name).

¿Cómo lo asigno para que las personas utilicen la siguiente clase PersonRole?

public class PersonRole {
    public virtual Person Person { get; set; }
    public virtual string Role { get; set; }
}

Actualizar:recompensa adicional, parece una pregunta útil no solo para mí.

¿Fue útil?

Solución

Personalmente, crearía una clase de rol como Yassir

Pero si desea utilizar la estructura que tiene en este momento, cree una vista que contenga la Clave extranjera de su Tabla de personas y la Descripción del rol.

Modifique la tabla Establecer mapeo para apuntar a su nueva vista Luego modifique su asignación de roles para que sea una propiedad en lugar de la asignación de muchos a uno.

Sin embargo, adoptar este enfoque creo que significará que no podrá actualizar su función, ya que está volviendo a aparecer en una vista.

Editar: Para actualizar el rol, puede agregar <sql-insert>,<sql-update> and <sql-delete> a su archivo de mapeo para que la cascada funcione todo

Otros consejos

En realidad, no obtendrá la respuesta que espera, simplemente porque no es posible.(N)Hibernate es un marco y soporte de mapeo relacional de objetos tres tipos de mapeo estrategias:

  • tabla por jerarquía de clases
  • tabla por subclase
  • tabla por clase concreta

También le permite desviarse de esto usando formula o sql-insert etc, pero como habrás descubierto, estos sólo te causan más dolor al final, no son recomendados por la comunidad de Hibernate y son malos para el mantenimiento de tu código.

¿Solución?

En realidad, es muy sencillo.No deseas utilizar una clase para Role.Supongo que quieres decir que no quieres exponer una clase de tipo Rol y que no quieres tener que escribir prObject.Role.Name todo el tiempo.Justo prObject.Role, que debería devolver una cadena.Tienes varias opciones:

  1. Utilice una clase interna en, digamos, PersonRole; esta clase puede ser interna o privada.Agregue una propiedad Rol que establezca y actualice un campo de miembro;
  2. Utilice una clase interna.Agregue una propiedad Rol que establezca y actualice un campo de miembro;

Examinemos la opción 2:

// mapped to table Role, will not be visible to users of your DAL
// class can't be private, it's on namespace level, it can when it's an inner class
internal class Role 
{
    // typical mapping, need not be internal/protected when class is internal
    // cannot be private, because then virtual is not possible
    internal virtual int Id { get; private set; }
    internal virtual string Name { get; set; }
}

// the composite element
public class PersonRole
{
    // mapped properties public
    public virtual Person Person { get; set; }

    // mapped properties hidden
    internal virtual Role dbRole { get; set; }

    // not mapped, but convenience property in your DAL
    // for clarity, it is actually better to rename to something like RoleName
    public string Role     /* need not be virtual, but can be */
    { 
        get
        {
            return this.dbRole.Name;
        }
        set
        {
            this.dbRole.Name = value;    /* this works and triggers the cascade */
        }
    }
}

Y el mapeo puede verse como se esperaba.Resultado:no has violado la regla de una mesa por clase (EDITAR:El autor de la pregunta dice que quiere violar explícitamente esa regla y Hib la apoya, lo cual es correcto.), pero ha ocultado los objetos para que no puedan modificarse ni accederse mediante el uso de técnicas típicas orientadas a objetos.Todas las funciones de NH (cascada, etc.) siguen funcionando como se esperaba.

(N)Hibernate tiene que ver con este tipo de decisiones:cómo crear una capa de abstracción segura y bien pensada para su base de datos sin sacrificar la claridad, la brevedad o la mantenibilidad ni violar las reglas de OO u ORM.


Actualización (después de q.estaba cerrado)

Otros enfoques excelentes que utilizo mucho cuando trato este tipo de problema son:

  • Cree sus asignaciones normalmente (es decir, una clase por tabla, sé que no le gusta, pero es lo mejor) y use métodos de extensión:

     // trivial general example
     public static string GetFullName(this Person p)
     {
         return String.Format("{0} {1}", p.FirstName, p.LastName);
     }
    
     // gettor / settor for role.name
     public static string GetRoleName(this PersonRole pr)
     {
         return pr.Role == null ? "" : pr.Role.Name;
     }
     public static SetRoleName(this PersonRole pr, string name)
     {
         pr.Role = (pr.Role ?? new Role());
         pr.Role.Name = name;
     }
    
  • Cree sus asignaciones normalmente pero use partial classes, que le permiten "decorar" su clase como desee.La ventaja:Si utiliza el mapeo generado de sus tablas, podrá regenerarlas con la frecuencia que desee.Por supuesto, las clases parciales deben ir en archivos separados, por lo que considerando su deseo de disminuir la "hinchazón", probablemente este no sea un buen escenario actualmente.

     public partial class PersonRole
     {
         public string Role {...}
     }
    
  • Quizás lo más simple:solo sobrecarga ToString() para Role, lo que lo hace adecuado para su uso en String.Format y amigos, pero por supuesto no lo hace asignable.Por defecto, cada clase de entidad o POCO debe tener un ToString() sobrecarga de todos modos.

Aunque es posible hacer esto directamente con NHibernate, el q.Se cerró antes de que tuviera tiempo de verlo (nadie tiene la culpa, simplemente no tuve tiempo).Actualizaré si encuentro tiempo para hacerlo a través del mapeo de Hibernate HBM, aunque no estoy de acuerdo con el enfoque.No es bueno luchar con conceptos avanzados de Hib cuando el resultado final es menos claro para otros programadores y menos claro en general (¿dónde quedó esa tabla?¿Por qué no hay una abstracción IDao para esa tabla?Ver también Mejores prácticas de NHibernate y S#arp).Sin embargo, el ejercicio es interesante.

Teniendo en cuenta los comentarios sobre las "mejores prácticas":en situaciones típicas, no debería ser solo "una clase por tabla", sino también un IDaoXXX, un DaoConcreteXXX y un GetDaoXXX para cada tabla, donde se utiliza la jerarquía de clase/interfaz para diferenciar entre tablas de solo lectura y de lectura/escritura.Eso es un mínimo de cuatro clases/líneas de código por tabla.Por lo general, esto se genera automáticamente, pero brinda una capa de acceso (dao) muy clara a su capa de datos (dal).Es mejor mantener la capa de datos lo más espartana posible.Ninguna de estas "mejores prácticas" le impide utilizar métodos de extensión o métodos parciales para mover Role.Name en Role.

estos son los mejores general prácticas.No siempre es posible, factible o incluso necesario en determinadas situaciones especiales o típicas.

no creo que sea posible asignar muchos a uno a un tipo primitivo si fuera usted, agregaría una clase de Rol al modelo

Este es el mayor apagón de todo el asunto del purista OO. Seguramente el objetivo es tener una aplicación que funcione. No es una versión de una jerarquía de clases perfecta. Entonces, ¿qué pasa si tiene que codificar & Quot; prObject.Role.Name & Quot; en lugar de " prObject.Role " ;. ¿Cómo te ayuda esto a hacer un programa mejor y más confiable?

Desde el punto de vista purista del diseño de la aplicación, lo que quiere es simplemente incorrecto. Una persona puede tener varios roles, un rol generalmente puede asignarse a varias personas. ¿Por qué tomarse todas estas molestias para imponer una jerarquía de clase irreal de un solo rol por persona cuando el modelo de datos de recuperación es de muchos roles por persona?

Si realmente tiene un " solo un rol por persona " regla entonces debería reflejarse en el modelo de datos subyacente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top