Сохранение и запрос элементов в Nhibernate

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

Магазин

class Store
{
    public virtual int StoreID { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<Item> ItemID { get; set; }
}

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

Пункт

class Item
{
    public virtual int ItemID { get; set; }
    public virtual string Name { get; set; }
    public virtual double Price { get; set; }
    public virtual int Quantity { get; set; }
    public virtual Store StoreID { get; set; }        
}

Сопоставления с Fluent Nhiberate следующие.

StoreMap

class StoreMap : ClassMap<Store>
{
   public StoreMap()
   {
       Id(x => x.StoreID).Column("idStore").GeneratedBy.Assigned();
       Map(x => x.Name).Column("Name").Not.Nullable();

       HasMany(x => x.ItemID).KeyColumn("idItem").Inverse().Table("Item").AsSet().Cascade.SaveUpdate();
    }
}

ItemMap

class ItemMap : ClassMap<Item>
{
    public ItemMap()
    {
       Id(x => x.ItemID).Column("idItem").GeneratedBy.Assigned();
       Map(x => x.Name).Column("Name").Not.Nullable();
       Map(x => x.Price).Column("Price").Default("0");
       Map(x => x.Quantity).Column("Quantity").Default("0");
       References(x => x.StoreID).Column("idStore");
    }
}

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

Store s = new Store{...}
Item i1 = new Item {
     Name = "Item 1",
     ItemID = 1,
     Price = 100,
     Quantity = 1,
     StoreID = s
};
Item i2 = new Item {
     Name = "Item 2",
     ItemID = 2,
     Price = 100,
     Quantity = 1,
     StoreID = s
};
trans = session.BeginTransaction();
session.SaveOrUpdate(s);
session.SaveOrUpdate(i2);
session.SaveOrUpdate(i1);
//Commit changes
trans.Commit();
session.Flush();
session.Close();

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

Store s = session.QueryOver<Store>().Where(x => x.StoreID == 1).SingleOrDefault<Store>();

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

Следует отметить, что в качестве альтернативы можно просто добавить элементы в коллекцию хранилища Items, а затем вам нужно будет только сохранить сущность Store (благодаря Cascade.SaveUpdate() в сопоставлении элементов хранилища).

blins 03.05.2018 12:16

Вы уже правильно используете cascade(Я использую все с сиротами, но ..). Это означает, что нет необходимости вызывать сеанс сохранения элементов. Они будут сохраняться .. только если мы также добавим их в коллекцию Магазина Items

Radim Köhler 03.05.2018 12:16

Хорошо, я изменил это, добавив элементы Item в список списка Store. Но у меня все еще не может быть обоих элементов в списке, когда я запрашиваю элемент Store с помощью Store s = session.QueryOver<Store>().Where(x => x.StoreID == 1).SingleOrDefault<Store>();.

a.ras2002 04.05.2018 10:03
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
353
1

Ответы 1

  • Для сохранения, поскольку вы сопоставили объекты, в частности, из-за установленной опции каскада (.Cascade.SaveUpdate()), вы можете удалить session.SaveOrUpdate(i2); и session.SaveOrUpdate(i1);. Просто сохранение s сохранит их автоматически.

  • Чтобы сохранить семантику объектно-ориентированного подхода, вам необходимо добавить файлы item в файл `store. Фактически, это означает добавление этих двух строк:

    s.ItemID.Add(i1);
    s.ItemID.Add(i2);
    
  • Вы можете использовать оператор using, чтобы аккуратно упростить создание и уничтожение (закрытие) сеанса.

Окончательный код будет таким:

    Store s = // as defined earlier;
    Item i1 = // as defined earlier;
    Item i2 = // as defined earlier;

    s.ItemID.Add(i1);
    s.ItemID.Add(i2);

    using (var session = NhConfig.GetSession())
    {
        var trans = session.BeginTransaction();
        try
        {
            session.SaveOrUpdate(s);

            trans.Commit();
        }
        catch (Exception)
        {
            trans.Rollback();
            throw;
        }
    }

    // Later when you need to query
    using (var session = NhConfig.GetSession())
    {
        Store store = session.QueryOver<Store>().Where(x => x.StoreID == 1).SingleOrDefault();
        foreach (var item in store.ItemID) // store.ItemID.Count == 2.
        {
            Console.WriteLine($"Item - Id: {item.ItemID}. Name: {item.Name}. Store ID: {item.StoreID.StoreID}.");
        }
        /* The above loop will print:
           Item - Id: 1. Name: Item 1. Store ID: 1.
           Item - Id: 2. Name: Item 2. Store ID: 1.
        */
    }

О файлах сопоставления ...

ItemMap может оставаться таким, каким вы его определили. Однако в StoreMap есть небольшая ошибка, которую необходимо исправить.

Измените строку:

HasMany(x => x.ItemID).KeyColumn("idItem").Inverse().Table("Item").AsSet().Cascade.SaveUpdate();

к

HasMany(x => x.ItemID).KeyColumn("idStore").Inverse().AsSet().Cascade.SaveUpdate();

Обратите внимание, что изменилось: .KeyColumn теперь называется "idStore" вместо "idItem". Имя ключевого столбца на стороне .HasMany(...) должно соответствовать имени столбца на стороне .References(...).

.Table("Item") является избыточным, поскольку по умолчанию «Item» будет именем таблицы для класса с именем Item. Поскольку вы не испортили имя таблицы в ItemMap, применяется правило по умолчанию (если вы не реализовали Convention для имен классов / таблиц).

Заключительные примечания:

  1. NHibernate теперь поддерживает IQueryable<T> - session.Query<T>(); так что вы можете использовать его вместо session.QueryOver<T>(). Если ты уже привык писать запросы Linq или если вы пришли из EF мир, вы можете просто продолжать писать запросы Linq, как вы обычно делаю. Бывают случаи, когда Linq не отвечает вашим потребностям, и вам приходится использовать QueryOver. Еще меньше случаев, когда QueryOver не удовлетворит ваши потребности, и вам придется использовать CreateCriteria. Иногда ничего из этого вам не подходит, и вам приходится писать необработанный sql. Но в большинстве случаев, в том числе и в этом случае, Linq доставит вас туда, куда вы собираетесь.
  2. NHibernate также теперь поддерживает шаблон async/await. Все, что вам нужно, это добавить using NHibernate.Linq;, и они станут доступны. Для этого кода вы можете использовать API-интерфейсы SaveOrUpdateAsync() и SingleOrDefaultAsync() вместо неасинхронных версий.
  3. Поскольку вы используете Fluent NHibernate, подумайте об использовании AutoMapping. Поверьте, писать файлы сопоставления - неинтересно, и вы хотите писать только один, когда это абсолютно необходимо.

Другие вопросы по теме