Нужны некоторые пояснения по отношениям NHibernate многие к одному

не могли бы вы помочь мне лучше понять, что делать с отношениями между моими сущностями и NHibernate?

У меня есть некоторые трудности, чтобы понять, какие операции мне нужно сделать вручную, и какие операции NHibernate сделает за меня (или нет).

У меня есть эти 2 сущности:

public class Position : BaseEntity<int, Position>
{
    private IList<Player> allPlayers = new List<Player>();

    public Position()
    {

    }

    public Position(string name, int number)
        : this()
    {
        Name = name;
        Number = number;
    }

    public string Name { get; set; }
    public int Number { get; set; }
}

а также

public class Player : BaseEntity<int, Player>
{
    public Player()
    {
        Visible = true;
    }

    public Player(string firstName, string lastName, int defaultNumber, Sex sex = Sex.Male, Position defaultPosition = null)
        : this()
    {
        FirstName = firstName;
        LastName = lastName;
        DefaultNumber = defaultNumber;
        Sex = sex;
        DefaultPosition = defaultPosition;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Position DefaultPosition { get; set; }
}

Вот беглые отображения:

public class PositionMap : ClassMap<Position>
{
    public PositionMap()
    {
        Id(pp => pp.Id)
            .GeneratedBy.Increment();

        Map(pp => pp.Name)
            .Not.Nullable();

        Map(pp => pp.Number)
            .Not.Nullable();

        HasMany<Player>(Reveal.Member<Position>("allPlayers"))
            .Access.CamelCaseField();
    }
}

public class PlayerMap : ClassMap<Player>
{
    public PlayerMap()
    {
        Table("Players");

        Id(p => p.Id)
            .GeneratedBy.Increment();

        Map(p => p.FirstName)
            .Not.Nullable()
            .UniqueKey("Players_Unique_FirstName_LastName");

        Map(p => p.LastName)
            .Not.Nullable()
            .UniqueKey("Players_Unique_FirstName_LastName");

        References(p => p.DefaultPosition);
    }
}

Как видите, у одного игрока есть одна позиция, но может не быть позиции (поэтому DefaultPosition может принимать значение NULL).

Вот мои вопросы:

  1. Когда я связываю позицию с DefaultPosition игрока, я должен делать это с помощью вспомогательных методов в Position? (например, AddPlayer, DeletePlayer...)

Я хотел бы, чтобы при удалении позиции все игроки, у которых есть эта позиция, вместо этого имели нулевое значение DefaultPosition.

  1. Должен ли я вручную очищать поле allPlayers позиции и вручную устанавливать нуль для всех связанных игроков DefaultPosition, или NHibernate позаботится об этом за меня?

  2. Почему NHibernate выполняет только DELETE FROM Positions WHERE Id... и не обновляет поле DefaultPOSition соответствующих игроков? Я пытался добавить Cascade.Delete в HasMany в PositionMap, но это ничего не меняет. Должен ли я запускать собственный запрос, который делает это?

заранее спасибо


person Emidee    schedule 29.06.2010    source источник


Ответы (1)


Q1 Если вы добавите свойство для Players on Position, вам не нужны эти вспомогательные методы.

public class Position : BaseEntity<int, Position>
{
    private IList<Player> allPlayers = new List<Player>();

    //read only
    public IList<Player> Players { get { return allPlayers;} }

    //... rest of class omitted
}

затем вызовите как:

var position = new Position();
position.Players.Add(new Player());

Q2, Q3 у вас может быть вспомогательный метод для упрощения позиции.

что-то типа:

public class Position : BaseEntity<int, Position>
{
    public void RemoveAll()
    {
       // null out the position on players
       foreach(var player in allPlayers)
       {
           player.Position = null; // SETS PositionId FIELD IN PLAYER TABLE TO NULL
       }
       allPlayers.Clear();
    }

    // ... rest of class omitted
}

с вызовом, похожим на:

using(var session = SessionFactory.GetCurrentSession())
{
   using(var tx = session.BeginTransaction())
   {
      position.RemoveAll();
      position.Delete();
      tx.Commit();
   }
}

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

person Tim Hoolihan    schedule 29.06.2010
comment
Тогда как мне обновить игроков в базе данных с нулевыми идентификаторами позиций? Обновлять их отдельно в рамках сеанса? Или с HQL? - person Emidee; 30.06.2010
comment
Функция RemoveAll очищает отношения моих сущностей. Но когда я сохраняю удаление позиции, NHibernate автоматически не устанавливает NULL в поле PositionId таблицы Players для каждого игрока, у которого есть эта позиция. Так и мой вопрос. Есть ли способ заставить NHibernate делать это автоматически, или мне следует добавить собственный запрос для выполнения этого обновления после удаления позиции? - person Emidee; 01.07.2010
comment
Наверное, я не знаю, как еще это сказать? Приведенный выше код делает то, что вы просите, зачем вам нужен пользовательский запрос? Игроки являются объектами nhibernate, поэтому, когда их позиция установлена ​​в нулевое значение и транзакция зафиксирована, их positionId в базе данных в этот момент будет нулевым. И position.Delete позаботится об удалении. Таким образом, в конце этого кода вы удалите позицию, и идентификатор позиции всех игроков будет нулевым, что вы и просите. Что касается nhibernate, делающего это автоматически, этого не произойдет. Как говорится в сообщении, Cascade предназначен для удаления, а не для обнуления. - person Tim Hoolihan; 01.07.2010
comment
я добавил комментарий для акцента, где в примере для PositionID устанавливается значение null - person Tim Hoolihan; 01.07.2010
comment
Можешь не гадать, это моя ошибка... Я забыл раскомментировать строку в своем коде :/ И действительно, теперь NHibernate обновляет игроков с NULL для их позиции. В любом случае, у меня есть еще несколько вопросов :) Я установил Inverse на HasMany(pp => pp.Players) в PositionMap. Но если я добавлю 2 игроков в позицию, а затем удалю позицию, NHibernate сделает 2 запроса на обновление игроков вместо одного глобального обновления, например: UPDATE Players SET PositionId = NULL WHERE PositionId = @p0; Это нормальное поведение? Или есть способ заставить NHibernate делать только одно обновление? - person Emidee; 01.07.2010
comment
вы можете сделать sql-запрос с чем-то вроде var query = session.CreateQuery (обновление Player set PositionId = null, где PositionId = :PositionId); query.SetParameter(PositionId, Position.Id); запрос.ВыполнитьОбновление(); транзакция.Коммит(); Или вы можете посмотреть сохраненный процесс, который делает это и удаляет позицию. См. ayende.com/Blog/archive/2006/09/18/< /а> - person Tim Hoolihan; 01.07.2010