2010-04-20 1 views
11

Я сопоставляю набор классов членства для своего приложения, используя Fluent NHibernate. Я сопоставляю классы с базой данных членства asp.net. Схема базы данных, относящаяся к проблеме, выглядит следующим образом:Fluent NHibernate - Как сопоставить недействительный внешний ключ, который существует в двух связанных таблицах

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

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

Между этими двумя таблицами существует взаимно-однозначная взаимосвязь. Я пытаюсь соединить две таблицы вместе и картографические данные из обеих таблиц в единое целое «User», который выглядит следующим образом:

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

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

Мой файл отображение следующим образом:

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

Если Я пытаюсь запустить код выше. Я получаю исключение FluentConfiguration.

Пытался добавить свойство 'ApplicationId', когда уже добавлено.

Если я удалю строку «Карта (user => user.ApplicationId);» или изменить его на «Карта (user => user.ApplicationId) .No.Update(). Not.Insert();« », то приложение запускается, но я получаю следующее исключение при попытке вставить нового пользователя :

Невозможно вставить значение NULL в столбец «ApplicationId», таблицу «ASPNETUsers_Dev.dbo.aspnet_Users»; столбец не допускает нулей. INSERT терпит неудачу. Заявление было прекращено.

И если оставить .map (пользователь => user.ApplicationId) как это первоначально было и сделать одно из этих изменений в присоединиться .map (пользователь => user.ApplicationId) то я получаю одно и то же исключение выше, за исключением того, что исключение связано со вставкой в ​​таблицу aspnet_Membership.

Итак ... как это сделать, если я предполагаю, что я не могу изменить схему базы данных?

+0

Если я понимаю ваши таблицы схем, кажется, у вас есть составной ключ, состоящий из ** и ** userId и ApplicationId. Попробуйте определить составной ключ, а затем выполните сопоставление Join с помощью этого ключа. – Tahbaza

ответ

4

Я думаю, что у меня есть что-то, что работает.

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

     } 
    } 

Простите некоторые соглашения об именовании, когда прототипирования, я использую не-неоднозначных имен за правильностью-конвенции, чтобы избежать путаницы.

DDL У меня есть (из приведенного выше кода) и DDL из вывода asp.net (4.0) (с использованием aspnet_regsql.exe для создания DDL) кажутся согласованными (между двумя версиями).

Я должен поблагодарить этот пост: http://brunoreis.com/tech/fluent-nhibernate-hasone-how-implement-one-to-one-relationship/

Если вы сделаете какие-либо ухищрений, то оставьте их.

Но я смог сохранить приложение, пользователя и членство.

Однако, я думаю, что я немного отключаюсь от отношения User: Membership. Сценарий microsoft выглядит как «Имейте пользователя, но позволяйте этому пользователю иметь другой пароль для каждого приложения», что имеет смысл. Но иногда при использовании кода MembershipProvider (код MS, ничего не делать с NHibernate, я «чувствую», как иногда она принимает одно приложение.

Я чувствую, как MS DDL должен иметь уникальное ограничение на DBO. .. Membership (UserId, ApplicationID), но я не вижу в их DDL

в любом случае, это должно обеспечить некоторую пищу для размышлений

+0

+1 для использования неоднозначных имен –

0

ли вы попробовать наследование:

public class User 
.... 

public class Member : User 
.... 

?

Любая причина, по которой вы присоединяетесь к ApplicationId вообще? Я считаю, что это в обеих таблицах для справки. Поскольку UserId является Guid, он уникален. Если у вас есть ситуация, когда вам нужно хранить одного и того же пользователя для двух разных приложений, хорошо, что членство asp.net не может работать так, оно создало бы две записи разных пользователей. Поиск по имени пользователя/паролю проверяет идентификатор приложения на основе настройки веб-приложений (машинный ключ), чтобы обеспечить его уникальность. Таблица членства - красная селедка.

+0

Но иногда при использовании кода MembershipProvider (код MS, ничего общего с NHibernate, я «чувствую», как будто иногда он принимает одно приложение. – granadaCoder

+0

// Цитата //. есть ситуация, когда вам нужно хранить одного и того же пользователя для двух разных приложений, ну, вы не можете asp.net членство не работает так, оно создало бы две разные записи пользователей // End Quote Я с вами (BobTodd) , Как они устанавливают DDL для работы с 1 пользователем, N членством (пароль для каждого приложения), но на самом деле это не работает. Я думал, что они могли очистить его до 4.0, но я не Думаю, они это сделали. Иногда это сбивает с толку. // HasOne // Я думаю, что HasOne близок к членскому подклассу User, код по-разному, но DDL очень похож. – granadaCoder

Смежные вопросы