2010-04-20 12 views
11

Estoy mapeando un conjunto de clases de membresía para mi aplicación usando Fluent NHibernate. Estoy mapeando las clases en la estructura de la base de datos de miembros asp.net. El esquema de la base de datos relevante para el problema se ve así:Fluido NHibernate - Cómo mapear una clave foránea que no admite valores NULL que existe en dos tablas unidas

ASPNET_USERS 
UserId  PK 
ApplicationId FK NOT NULL 
other user columns ... 

ASPNET_MEMBERSHIP 
UserId  PK,FK 
ApplicationID FK NOT NULL 
other membership columns... 

Existe una relación de uno a uno entre estas dos tablas. Estoy intentando unir las dos tablas juntas y datos de los mapas de ambas tablas a una sola entidad 'Usuario' que se parece a esto:

public class User 
{ 
    public virtual Guid Id { get; set; } 
    public virtual Guid ApplicationId { get; set; } 

    // other properties to be mapped from aspnetuser/membership tables ... 

Mi archivo de asignación es la siguiente:

public class UserMap : ClassMap<User> 
{ 
    public UserMap() 
    { 
     Table("aspnet_Users"); 
     Id(user => user.Id).Column("UserId").GeneratedBy.GuidComb(); 
     Map(user => user.ApplicationId); 
     // other user mappings 

     Join("aspnet_Membership", join => { 
      join.KeyColumn("UserId"); 
      join.Map(user => user.ApplicationId); 
      // Map other things from membership to 'User' class 
     } 
    } 
} 

Si Intento ejecutar con el código anterior Obtengo una excepción FluentConfiguration

Intenté agregar la propiedad 'ApplicationId' cuando ya se agregó.

Si elimino la línea "Map (user => user.ApplicationId);" o cámbialo a "Map (user => user.ApplicationId) .Not.Update(). Not.Insert();" luego la aplicación se ejecuta pero obtengo la siguiente excepción al intentar insertar un nuevo usuario :

No se puede insertar el valor NULL en la columna 'ApplicationId', tabla 'ASPNETUsers_Dev.dbo.aspnet_Users'; la columna no permite nulos. INSERT falla La declaración ha finalizado.

Y si dejo la .MAP (user => user.ApplicationId) ya que originalmente era y hacer cualquiera de esos cambios a la unen .MAP (user => user.ApplicationId) luego recibo la misma excepción anterior, excepto por supuesto la excepción está relacionada con una inserción en la tabla aspnet_Membership

Entonces ... ¿cómo hago este tipo de mapeo suponiendo que no puedo cambiar el esquema de mi base de datos?

+0

Si entiendo sus tablas de esquema, parece que tiene una clave compuesta que consta de ** both ** userId y ApplicationId. Intente definir la clave compuesta y luego hacer la asignación Join usando esa clave. – Tahbaza

Respuesta

4

Creo que tengo algo que funciona.

public class Application 
    { 
     public virtual Guid ApplicationId { get; set; } 


     /* Scalar Properties of an Application */ 
     public virtual string ApplicationName { get; set; } 
     public virtual string Description { get; set; } 

     public virtual string LoweredApplicationName 
     { 
      get 
      { 
       return this.ApplicationName.ToLower(); 
      } 
      set 
      { 
       if (String.IsNullOrEmpty(this.ApplicationName)) 
       { 
        this.ApplicationName = value; 
       } 
      } 
     } 

     public virtual IList<Membership> TheManyMemberships { get; protected set; } 

    } 


    public class User 
    { 
     public virtual Guid Id { get; set; } 
     public virtual Application TheApplication { get; set; } 

     public virtual Membership TheMembership { get; set; } 

     /* Scalar Properties of a User */ 
     public virtual string UserName { get; set; } 
    } 


    public class Membership 
    { 
     private Guid UserId { get; set; } 
     private User _theUser { get; set; } 

     protected Membership() { } 

     public Membership(User theUser) 
     { 
      _theUser = theUser; 
     } 

     public virtual Application TheApplication { get; set; } 

     /* Scalar Properties of a Membership */ 
     public virtual string Password { get; set; } 
} 





    public class ApplicationMap : ClassMap<Application> 
    { 
     public ApplicationMap() 
     { 
      Table("aspnet_Applications"); 
      Id(app => app.ApplicationId).Column("ApplicationId").GeneratedBy.GuidComb(); 
      Map(x => x.ApplicationName); 
      Map(x => x.LoweredApplicationName); 
      Map(x => x.Description); 

      HasMany<Membership>(x => x.TheManyMemberships) 
       .Inverse() 
       .AsBag(); 
     } 
    } 


    public class UserMap : ClassMap<User> 
    { 
     public UserMap() 
     { 
      Table("aspnet_Users"); 
      Id(user => user.Id).Column("UserId").GeneratedBy.GuidComb(); 
      References(x => x.TheApplication, "ApplicationId") 
        .Not.Nullable(); 

      HasOne(x => x.TheMembership) 
      .Cascade.All();// 
      //.Constrained(); 

      Map(x => x.UserName).Not.Nullable(); 

     } 
    } 


    public class MembershipMap : ClassMap<Membership> 
    { 
     public MembershipMap() 
     { 
      Table("aspnet_Membership"); 

      Id(Reveal.Member<Membership>("UserId")) 
       .GeneratedBy.Foreign("_theUser"); 
      HasOne(
       Reveal.Member<Membership, User>("_theUser")) 
        .Constrained() 
        .ForeignKey(); 

      References<Application>(x => x.TheApplication, "ApplicationId") 
      .Not.Nullable(); 

      Map(x => x.Password); 

     } 
    } 

Perdona algunas de las convenciones de nomenclatura, cuando la creación de prototipos, utilizo nombres no-ambiguas sobre adecuada a la convención para evitar confusiones.

El DDL que tengo (desde el código anterior) y el DDL de la salida de asp.net (4.0) (usando aspnet_regsql.exe para compilar el DDL) parecen consistentes (entre las dos versiones).

tengo que agradecer a este mensaje: http://brunoreis.com/tech/fluent-nhibernate-hasone-how-implement-one-to-one-relationship/

Si realiza ajustes, emvía ellos.

Pero pude guardar una Aplicación, Usuario y Membresía.

Sin embargo, creo que puedo estar un poco apagado con el usuario: la relación de membresía. El escenario de Microsoft parece ser "Tener un usuario, pero permitir que ese usuario tenga una contraseña diferente para cada aplicación", lo cual tiene sentido. Pero a veces cuando se utiliza el código de MembershipProvider (el código MS, nada que ver con NHibernate, que "sentir" como a veces se asume una sola aplicación.

me siento como el MS DDL debe tener una restricción única en DBO. .. de miembros (identificación de usuario, Id de Aplicación), pero yo no lo ven en su DDL

en cualquier caso, esto debería proporcionar algunos elementos de reflexión

+0

+1 para usar nombres no ambiguos –

0

¿usted intentó herencia:

public class User 
.... 

public class Member : User 
.... 

?

¿Alguna razón por la que se está uniendo a ApplicationId en absoluto? Creo que está en ambas tablas como referencia. Como UserId es un Guid, es único. Si tiene la situación en la que necesita almacenar el mismo usuario para dos aplicaciones distintas, así no puede ser miembro de asp.net no funciona así, crearía dos registros de usuarios distintos. La búsqueda en el nombre de usuario/contraseña comprueba la id de la aplicación en función de la configuración de las aplicaciones web (clave de la máquina) para habilitar su exclusividad. La tabla de membresía es una pista falsa.

+0

Pero a veces, cuando uso el código MembershipProvider (el código MS, nada que ver con NHibernate, me "parece" que a veces asume una sola aplicación. – granadaCoder

+0

// Cita //. Si lo hace tiene la situación en la que necesita almacenar el mismo usuario para dos aplicaciones distintas, así que no puede la membresía asp.net no funciona así, crearía dos registros de usuarios distintos // Fin de cita estoy con usted (BobTodd) Es como configurar el DDL para trabajar con 1 usuario, N membresías (una contraseña de diferencia por aplicación), pero en realidad, no funciona así. Pensé que podrían haberlo limpiado para 4.0, pero no lo hago Creo que lo hicieron. Es confuso a veces. // HasOne // Creo que HasOne está cerca del Miembro que subclasifica al Usuario, el código es diferente, pero DDL es muy similar. – granadaCoder

Cuestiones relacionadas