NHibernate, сопоставьте коллекцию, где ключ может быть двух разных столбцов - PullRequest
0 голосов
/ 02 января 2012

Есть сущность A .

Кроме того, существует сущность B , которая имеет две ассоциации с A .

A имеет коллекцию B .

Эта коллекция должна загружать любые B , если один из связанных A является родительским для загруженного A .

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

Как мне этого добиться?

Примечание. Заказ не имеет значения, поэтому вы можете предложить составить карту, используя bag .

Примечание 2. Пожалуйста, предложите, как добиться этого с помощью сопоставления XML, я не буду делать это в коде.

ОБНОВЛЕНИЕ: Реальный сценарий:

это все о реализации дружбы. Я хочу отобразить коллекцию дружбы в сущности UserProfile. У дружбы есть две ассоциации, представляющие отношения: OneUser, OtherUser. Если я хочу, чтобы у меня были все друзья, мне нужно проверить оба свойства, потому что один - мой друг, если одно из обоих свойств принадлежит мне.

Ответы [ 2 ]

1 голос
/ 02 января 2012

Если вы готовы немного переместить решение из области данных, ваши пользователи могут иметь отношение один ко многим других пользователей, которых они назначили друзьями.Это может быть protected или private, если вы не хотите, чтобы он просачивался.

Затем вы реализуете открытое свойство, которое определяет фактическую Friendship как требующую отношения воба направления.Может быть что-то вроде:

public List<User> Friends {
    this.assignedFriends.Where(f => f.assignFriends.Contains(this)).ToList();
}

Если вы сделаете это, вы захотите убедиться, что используете форму кэша 2-го уровня, в противном случае запросы к этому свойству забьют вашу базу данных.


Если вместо этого вам нужно вернуть коллекцию выделенного объекта Friendship, это зависит от того, как вы сохраняете эти записи и как вы отобразили этот класс.

Один из вариантов - определить Friendship, чтобы просто иметь три столбца, первичный ключ и два внешних ключа обратно в таблицу User.Затем вам потребуется немного логики, когда кто-то пытается добавить друга: сначала нужно проверить, существует ли уже половина отношений.

var f = session.Query<Friend>()
    .Where(x => x.User1 == YourCurrentUser)
    .Cacheable()
    .FirstOrDefault();

, затем, если она существует, вы назначаете другую половинуотношения

f.User2 = TheOtherUser;

в противном случае создайте новый объект:

f = new Friendship();
f.User1 = YourCurrentUser;

и после любой ветви:

session.SaveOrUpdate(f);

тогда друзья User станут

public property List<Friendship> {
    session.Query<Friendship>()
        .Where(f => 
            f.User1 != null && f.User2 != null
            && (f.User1 == this || f.User2 == this)
        ).Cacheable()
        .ToList();
}

Обратите внимание, я не рядом с моей установкой VS.Пожалуйста, извините за опечатки или если я допустил явные грубые ошибки (сейчас 2:30, где я нахожусь)

1 голос
/ 02 января 2012

Это не совсем ответ, но мне нужно было иметь возможность форматировать и не иметь ограничения символов.

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

Несколько вещей, на которые я смотрел, которые казались многообещающими, были SQLQueries, которые возвращали объекты в качестве псевдонима, который был объединен с помощью Queryover.

Или - добавление предложения .Where к отображению hasMany. Все, что я прочитал об этой опции, говорит, что она очень ограничена. Хотя логика сделать то, что вы просите, кажется довольно простой - Select Distinct ... From ... Where (OneUser = UserId or OtherUser = UserId)

EDIT:

Посмотрите на JoinQueryOver здесь: http://nhibernate.info/blog/2009/12/17/queryover-in-nh-3-0.html

И собственные запросы SQL здесь: http://knol.google.com/k/nhibernate-chapter-14-native-sql#

Хотя это не решение уровня сопоставления, вы можете указать критерии в предложении where при выборе пользователей, чтобы их Друзья были заполнены правильно. Если вы не можете добиться необходимой фильтрации с помощью Fluent QueryOver, я думаю, что вы могли бы сделать псевдоним из запроса Native SQL и JoinQueryOver / JoinAlias ​​для соответствующего заполнения коллекции Friends.

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

** Редактировать 2: ** Я немного поиграл с этим, и это настолько близко, насколько я мог понять:

Public Class UserMapping
    Inherits ClassMap(Of User)
    Public Sub New()
        Id(Function(x) x.Id).Column("UserID")
        Map(Function(x) x.Name).Length(50).Not.Nullable().Column("UserName")
        HasMany(Function(x) x.Friends).Inverse.KeyColumn("UserID").Where("Users.UserID in (select Friendships.FriendOne from Friendships where Friendships.FriendTwo = UserID) or UserID in (select Friendships.FriendTwo from Friendships where Friendships.FriendOne = UserID)")
        Table("Users")
    End Sub
End Class

Запрос не совсем работает, потому что он продолжает накладывать дополнительное ограничение в предложении where, в котором UserID должен равняться внешнему userId, что противоречит цели подзапроса.

Я видел еще один пост, где предлагалось два других решения.

  1. Создание двух дочерних коллекций. Один, который отображает друзей, где текущий Пользователь является Основным другом, а другой, где текущий пользователь является Вторым другом. Затем вы можете создать свойство, которое будет объединять их вне того, как NH запрашивает его.

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

На основании этих двух вариантов - я бы, вероятно, выбрал вариант № 1.

...