Отношения один-к-одному на карте не позволяют вставлять

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

Users:

- UserID (PK, Identity)
- UserName
- Password

UsersDetails:

- UserID (PK, FK)
- FirstName
- LastName

Я создал следующие классы поко:

public class User {
    public virtual int UserID { get; set; }
    public virtual string UserName { get; set; }
    public virtual string Password { get; set; }
    public virtual UserDetails Details { get; set; }
}

public class UserDetails {
    public virtual int UserID { get; set; }
    public virtual User User { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }

    public UserDetails() {
    }

    public UserDetails(User user) {
        User = user;
    }
}

Которые легко отображаются (обратите внимание, что отображение xml очень похоже, и если все, что вы знаете, это отображение xml, я все равно буду признателен за ваше руководство):

public class UserMap : ClassMap<User> {
    public UserMap() {
        Table("Users");
        Id(x => x.UserID);
        Map(x => x.UserName);
        Map(x => x.Password);
        HasOne(x => x.Details)
            .Constrained()
            .Cascade.All();
    }
}

public class UserDetailsMap : ClassMap<UserDetails> {
    public UserDetailsMap() {
        Table("UsersDetails");
        Id(x => x.UserID)
            .GeneratedBy.Foreign("User");
        HasOne(x => x.User)
            .Constrained();
        Map(x => x.FirstName);
        Map(x => x.LastName);
    }
}

Все отображается правильно, но если я скажу:

var user = new User() { UserName = "Test", Password = "Test" };
user.Details = new UserDetails(user) { FirstName = "Test", LastName = "Test" };
session.Save(user);

Я получаю сообщение об ошибке:

"NHibernate.Id.IdentifierGenerationException: нулевой идентификатор, созданный для: UserDetails."

Я был бы очень признателен, если бы кто-нибудь мог показать мне, что я сделал не так. Спасибо

Изменить: любезно предоставлено Джейми Айдом. Я изменил отображение пользователя на:

public class UserMap : ClassMap<User> {
    public UserMap() {
        Table("Users");
        Id(x => x.UserID);
        Map(x => x.UserName);
        Map(x => x.Password);
        References(x => x.Details, "UserID")
            .Class<UserDetails>()
            .Unique();
    }
}

Но теперь, когда я вставляю пользователя, я получаю сообщение об ошибке:

«System.ArgumentOutOfRangeException: индекс вне допустимого диапазона. Должен быть неотрицательным и меньше размера коллекции».

Если я добавлю Cascade.All () в свою ссылку, я получаю исходную ошибку, которую я получал о сгенерированном нулевом идентификаторе.


person nfplee    schedule 11.01.2011    source источник


Ответы (5)


Я думаю, что Constrained следует указывать только в UserDetailsMap, а не в UserMap. Пытаться:

public class UserMap : ClassMap<User> {
    public UserMap() {
        Table("Users");
        Id(x => x.UserID);
        Map(x => x.UserName);
        Map(x => x.Password);
        HasOne(x => x.Details)
            .Cascade.All();
    }
}

РЕДАКТИРОВАТЬ:

См. this и это. Похоже, что вам нужно сопоставить отношения как «многие-к-одному» со стороны пользователя и «один-к-одному», ограниченные со стороны UserDetails, чтобы получить ленивую загрузку, работающую с «один-к-одному». Я не знаю, изменилось ли это в NH3.

person Jamie Ide    schedule 12.01.2011
comment
Ура, но ленивая загрузка не поддерживается, если вы не укажете ограничение на взаимно-однозначное отношение. - person nfplee; 12.01.2011
comment
После дальнейшего расследования. Похоже, это решает проблему, но ленивая загрузка по-прежнему не работает. Как только я хватаю пользователей, он захватывает и детали. - person nfplee; 12.01.2011
comment
Еще раз спасибо, я попытался сопоставить сторону пользователя, используя сопоставление многие-к-одному (я обновил свой исходный вопрос с новым сопоставлением). Но все равно не работает. Буду очень признателен за вашу помощь еще раз. Спасибо - person nfplee; 13.01.2011
comment
Попробуйте изменить сопоставление на: Ссылки (x = ›x.Details); - person Jamie Ide; 13.01.2011
comment
Это не сработает, поскольку в таблице Users нет поля DetailsID. - person nfplee; 13.01.2011

Я не уверен, что вы правильно отображаете свойство ID. Разве это не должен быть просто автоматически увеличиваемый идентификатор, и ваше сопоставление должно быть следующим:

Id(x=>x.UserId);

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

person Baz1nga    schedule 11.01.2011
comment
Ура, но поле UserID в таблице UsersDetails является ссылкой на таблицу Users, которая содержит автоматически увеличивающийся идентификатор. Поскольку это сопоставление «один-к-одному», идентификатор пользователя в таблице UsersDetails также является первичным ключом. Надеюсь, это поможет. - person nfplee; 11.01.2011

Я думаю, вам нужно иметь сопоставление идентификаторов внешнего ключа в сопоставлении User вместо UserDetails и собственного в UserDetails. Однако мне не удалось найти на него ссылку.

person Goblin    schedule 11.01.2011
comment
Спасибо за ваш ответ. Я только что нашел следующую статью (nhforge.org/blogs/nhibernate/archive/2011/01/08/) в блоге NHibernate. По сути, это то, чего я хочу достичь, но я до сих пор не вижу, чем отличается мое отображение. - person nfplee; 12.01.2011

http://gorbach.wordpress.com/2010/09/24/fluent-onetoone/

HasOne(x => x.Details).Cascade.All().ForeignKey("UserDetails");
HasOne(x => x.User).Constrained();
var user = new User() { UserName = "Test", Password = "Test" };
user.Details = new UserDetails(user) { FirstName = "Test", LastName = "Test" };
user.Details.User = user;
session.Save(user);
person kimyh00    schedule 14.02.2011

После дальнейшего исследования выяснилось, что это не будет работать в версии 2.0. Теперь я могу перейти на версию 3.0, где, как я полагаю, это теперь возможно.

person nfplee    schedule 23.05.2011