Свободный NHibernate - Как отобразить необнуляемый внешний ключ, который существует в двух соединенных таблицах - PullRequest
11 голосов
/ 21 апреля 2010

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

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

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

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

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) .Not.Update () .Not.Insert ();", затем приложение запускается, но я получаю следующее исключение при попытке вставить нового пользователя:

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

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

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

Ответы [ 2 ]

4 голосов
/ 16 декабря 2010

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

  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/

Если вы сделаете какие-либо изменения, то, пожалуйста, опубликуйте их.

Но мне удалось сохранить Приложение, Пользователя и Членство.

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

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

Несмотря на это, это должно дать пищу для размышлений.

0 голосов
/ 18 декабря 2010

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

public class User
....

public class Member : User
....

?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...