Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Nhibernate транзакция закоммичена, но записи в БД нет

Иногда Nhibernate транзакция закоммичена, но записи в БД нет.

Выполняется следующий код:
[Transaction]
public int CreateTrade(Trade trade)
{
    //validate and fill properties of trade
    _tradeRepository.SaveOrUpdate(trade);

    return trade.Id;
}


После выхода из метода возвращается идентификатор, однако, в БД нет записи с таким идентификатором. В тоже время никаких exception'ов не было, иначе бы они отловились.
Если смотреть лог nhibernat'а, то видно, что транзакция успешно закоммичена.
Воспроизводится очень редко, но проблема очень болезненна.

P.S. используется Nhibernate v4.0.2, уровень изоляции: Snapshot.
Ответ: ЕвгенийВ,

MSSQL
Вопрос: Nhibernate сессии

Подскажите, как правильно работать с сессиями в WinForms приложении. Решил поизучать hibernate, взял пример, в нем на каждый запрос открывается новая сессия. Например:
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
Contact contact = new Contact("Joe", "Jones", "jj@nhibernate.com");
session.Save(contact);
tx.Commit();

Нашел проект, в котором только одна сессия открывается при авторизации БД.
Попробовал реализовать с одной сессией, но в части кода при этом стала возникать постоянно ошибка.
Описание этой части:
1. Через селект получаем список id из таблицы по условию.
2. В цикле по всем id получаем через селект запись(объект) таблицы.
3. Апдейтим запись.

Как правильно?
Ответ:
saxix
Подскажите, как правильно работать с сессиями в WinForms приложении. Решил поизучать hibernate, взял пример, в нем на каждый запрос открывается новая сессия. Например:
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
Contact contact = new Contact("Joe", "Jones", "jj@nhibernate.com");
session.Save(contact);
tx.Commit();

Нашел проект, в котором только одна сессия открывается при авторизации БД.
Попробовал реализовать с одной сессией, но в части кода при этом стала возникать постоянно ошибка.
Описание этой части:
1. Через селект получаем список id из таблицы по условию.
2. В цикле по всем id получаем через селект запись(объект) таблицы.
3. Апдейтим запись.

Как правильно?

Забыл добавить, что та часть кода, которая выдает ошибку (при реализации на одной сессии) - работает не в потоке UI
Вопрос: NHibernate. После update не отображаются обновления в записях

Приветствую.
Есть записи, которые отображает программа. Во время выполнения некоторые поля в записи апдейтятся. Но обновления не отображаются в селектах. Помогает только перезагрузка программы (новая сессия). Почему такое может быть?
Ответ: ДАже не представлю какой код можно приложить
Получение списка записей
public IList<Data>  GetData(String data)
{
  ICriteria criteria = session.CreateCriteria<Data>("data");
  if (!String.IsNullOrWhiteSpace(data))
     criteria.Add(Restrictions.Eq("data.name", data));
  return criteria.List<Data>();
}

Запускаем программу, через данный метод получаем коллекцию Data. Ручками делаем апдейт в базе и, скажем, в data.name значение 1 меняем на значение 2. Не закрывая программу опять дергаем метод GetData("") - на выходе коллекция, но той записи, в которой производили апдейт data.name - старое значение. Однако если дергать метод GetData("2") - тоесть поиск по новому значению - запись будет найдена, но коллекции в поле data.name - старое значение
Переоткрыть программу - все ок.
Вопрос: NHibernate. Материализация данных

Суть проблемы изложена тут



I have old code to support. NHibernate is used to query DB. There are NHibernate LINQ queries like IQueryOver.Where and others. It works fine but I want to use these queries for local sequences. In Microsoft LINQ there is the method Enumerable.AsQueryable. Is there any analogue in NHibernate LINQ?

So I have this.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    private IQueryOver<Package> GetPackages(GetPackageMessage message)
            {
                var query = SessionFactory.Current.QueryOver<Package>();
 
                if (message.TzapUtc.Use)
                {
                   query = query.Where(x => x.Tzap_utc >= message.TzapUtc.ValueBegin);
 
                }            
                if (message.Iik.Use)
                {
                    query = use ? query.Where(x => x.Iik == message.Iik.Value);
                }
}
I need to apply all these Where to my local collection IEnumerable< Package>

instead of collection got from DB.
Кратко: есть последовательность выражений типа Where( ...) . Это не Enumerable Where а именно родные NHibernate.Linq. Мне хочется разделить на
запрос к БД с таким фильтром из Where
и фильтрация локальной коллекции IEnumerable<Package>.
В LINQ to SQL локальную коллекцию можно сделать .AsQuaryable и использовать на ней LINQ to SQL.
Вот пример из C# in a nutshell
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
IQueryable<Product> FilterSortProducts (IQueryable<Product> input)
{
return from p in input
where ...
order by ...
select p;
}
void Test()
{
var dataContext = new NutshellContext ("connection string");
Product[] localProducts = dataContext.Products.ToArray();
var sqlQuery = FilterSortProducts (dataContext.Products);
var localQuery = FilterSortProducts (localProducts.AsQueryable());
...
}
Код на NHibernate достался в наследство, в NHibernate почти не разбираюсь
Ответ: koperfild, я тоже не спец по NHibernate. Не знаю можно ли так делать.
Вопрос: Не отрабатывает выборка NHibernate ICriteria в ASP.NET MVC

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

Имеется вот такой класс:
    public class SosResearchFile
    {
        public virtual string Id { get; set; }  
        public virtual int TypeId { get; set; }
        public virtual string ResearchId { get; set; }

        public virtual byte[] FileData { get; set; }
        public virtual string FileName { get; set; }
        public virtual string Description { get; set; }
         
        public virtual byte[] GetDecodedFile()
        {
            byte[] file;
            TsosGdisDecoder.Decode(FileData, out file);
            return file;
        }        
    }


Вот такой класс маппер:
    class SosResearchFileMap:ClassMap<SosResearchFile>
    {
        public SosResearchFileMap()
        {
            ReadOnly();
            Table("SOSRESEARCHFILE");
            Id(x => x.Id, "RFID");
            Map(x => x.TypeId, "RFTYPEID");
            Map(x => x.ResearchId, "RFRESEARCHID");
            Map(x => x.FileData, "RFFILEDATA");//.LazyLoad();
            Map(x => x.FileName, "RFFILENAME");
            Map(x => x.Description, "RFDESCRIPTION");
        }
    }


Имеются такие таблицы в БД:
Таблица SOSRESEARCHFILE
-------------------------------------------
SOSRESEARCHFILE
-------------------------------------------
RFID VARCHAR2(22) - PK
RFTYPEID NUMBER(9)
RFFILEDATA BLOB - Nullable
RFRESEARCHID VARCHAR2(22) - FK на RESID таблицы SOSRESEARCH
RFFILENAME VARCHAR2(240) - Nullable
RFDESCRIPTION VARCHAR2(120) - Nullable
------------------------------------------


Таблица SOSRESEARCHGRAPH
-------------------------------------------
SOSRESEARCHGRAPH
-------------------------------------------
RGRID VARCHAR2(22) - PK
RGRRESEARCHID VARCHAR2(22) - FK на RESID таблицы SOSRESEARCH
RGRPICTURE BLOB	 - Nullable
RGRDESCRIPTION VARCHAR2(120) - Nullable
RGRTYPE NUMBER(9)
RGRSRC NUMBER(9)
RGRINDEX NUMBER(9) - Nullable
RGRMAIN NUMBER(1) - Nullable
RGRMETAFILE BLOB - Nullable
------------------------------------------


Таблица SOSRESEARCH
------------------------------------------------
SOSRESEARCH
------------------------------------------------
RESID VARCHAR2(22) - PK
... набор остальных полей таблицы
----------------------------------------------


Для таблицы SOSRESEARCHGRAPH запрос на выборку отрабатывает корректно, выглядит вот так:
        public IList<SosResearchGraph> GetResearchGraphs(string researchId)
        {
            var criteria = _session.Instance.CreateCriteria(typeof(SosResearchGraph));
                criteria.Add(Restrictions.Eq("ResearchId", researchId));
            var pictures = criteria.List<SosResearchGraph>();
            return pictures;
        }	


а для таблицы SOSRESEARCHFILE такой-же посути запрос не отрабатывает:
        public IList<SosResearchFile> GetResearchFiles(string researchId)
        {
            var criteria = _session.Instance.CreateCriteria(typeof(SosResearchFile));
            criteria.Add(Restrictions.Eq("ResearchId", researchId));
            var files = criteria.List<SosResearchFile>();
            return files;
        }


С случае для запроса к SosResearchFile даже не возникает NHibernate-запроса. Т.е. если смотреть в Nhibernate-лог, то для первого варианта перед отработкой метода и после него в логе появляются 2 NHibernate запроса и выборка производится, а во втором случае этих запросов в логе не возникает. Т.е. чего-то не хватает для того чтобы отработал NHibernate для второго класса (где-то, что-то не прописанов касаемо именно нового класса SosResearchFile, в плане маппинга может не так что-то, в силу чего NHibernate не создаёт запроса и не скидывает в лог информацию и т.д.) или не правильные сущности - но всё проверил в плане правильности имён таблиц и полей.

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

Т.е. где-то, что-то не доделано, а что не могу понять, бьюсь уже несколько дней. Помогите пожалуйста полностью понять весь процесс маппинга и разобраться с проблемой. Если интересуют другие данные по коду, настройки конфигов (Web.config - по теме, без паролей конечно и строк подключения) и т.д. приведу без проблем, наверняка того, что я выложил будет не достаточно. Прошу помощи экспертов, заранее благодарен за помощь.
Ответ: [quot Nikolay Kormushkin]
maratoss
Nikolay Kormushkin,
...Конструктор мапкласса не был public...

Вернее не конструктор, а сам мап-класс
Вопрос: Nhibernate и безысходность Fetch + Take

            model.Collection = q.Skip(99).Take(15);


и всё прекрасно


но стоит добавить Fetch вложенных коллекций и вместо ожидаемых 15 элементов будет меньше
понятно что он тупой и считает по общему количеству записей которых становится больше с каждым джойном

что можно делать?

фишка в том, что я использую отличную удобную либу PagedList вместо ручных skip take
Ответ:
Onax
Это с какого перепуга оно зло? если мне нужен List<Person> и я абсолютно точно знаю что использую его связь Addresses как же беж фетча/инклуда?
Вместо 1 селекта с джойном пойдет 100500 мелких дерганий базы


Мне нужны определённые данные из БД, меня абсолютно не должны парить какие-то фетчи/инклюды. Зачем я буду париться из-за того, что с чем связано, если мне нужны весьма конкретный набор данных, а не целый фрактал связанных данных. Решается это легко, с помощью проекций, а убожеский костыль типа кривых инклюдо-фетчей идут лесом. Кроме того, в бизнес не должны вываливаться EF/NH сущности, так что ещё и поэтому инклюды не упали нафиг.
Вопрос: Начать работать с nHibernate

Здравствуйте!
Помогите, пожалуйста начать работу с nHibernate. Добавил в проект nHibernate с помощью NuGet. В статье, по которой учусь нужно подключить в проект NHibernate.dll и nunit.dll, которых не нахожу в папке C:\Program Files\Microsoft SQL Server Compact Edition\v4.0. Подскажите, в чём проблема, я что-то не доустановил или как?
Ответ: Да, есть, спасибо за помощь!
Вопрос: nhibernate как сделать join с дополнительной таблицей в mapping?

Столкнулся с проблемой что NH втихаря генерирует плохой запрос с IN, который казалось бы не должен возникать, но NH думает что так лучше :)
Рассмотрим такую схему классов:
class User{
    public IList<Payment> Payments {get;set;}
}
class Payment{
    public User User {get;set;}
    public Product Product  {get;set;}
    public decimal Sum {get;set;}
}
class Product{
    public Name {get;set;}
}

Для User объявлен маппинг:
mapping.HasMany(x => x.UserServicePayments)


Получается что при первом обращении к User.Payments в эту коллекцию загружаются все оплаты пользователя. Все работает как задумано и все последующие запросы типа:
user.Payments.Where(x=>x.Sum > 1000).ToArray() 

работают как положено, не генерируя лишний SQL, т.к. все Payment в коллекции.

НО! Когда я делаю запрос чуть глубже чем Payment, например:
user.Payments.Where(x=>x.Product.Name == n).ToArray()

то это приводит к генерации очень плохого запроса. NH берет все ProductId из коллекции user.Payments и запрашивает их:
select * from Product where id in (1,2,3,3,4... тут все id из user.Payments)
в плане такой запрос не позволяет использовать индекс, т.к. IN достаточно длинный, что приводит к full scan и падению системы по timeout. Вручную написать запрос с хинтом WITH(INDEX(MyIndex)) - не вариант.

Выходом я вижу как-то указать в маппинге для User, что вместе с Payment для поля Payments нужно загрузить ещё и Product. Примерно так:
mapping.HasMany(x => x.UserServicePayments).Join(x=>x.Product)
Но как это написать на fluetn nhibernate не пойму.
Спасибо!
Ответ: Ларчик то просто открывался, ребята.
Можно ведь указать чтобы Payment всегда джойнил Product с помощью:
paymentMapping.References(x => x.Product).Fetch.Join();

Это приводит к жадному джойну с продуктами, хотя местами это замедлит работу, но с целом в моем случае это спасение.
Удивительно, что это не помогало:
paymentMapping.References(x => x.Product).Not.LazyLoad();
Вопрос: Правильно ли исполнены паттерны UnitOfWork и Repository для Nhibernate?

Изучал использования NHibernate и паттернов и в итоге пришел к такому коду, это тестовый набросок, хочу подобное использовать в одном солюшене в котором будут два проекта, один в виде сервисов, другой в виде ASP.NET MVC. Задаю вопрос с целью понять, правильно ли я понял эти паттерны, правильно ли их использовал и не лишние ли они вообще и можно было все не усложнять?
Исходный код (в виде одного файла, для запуска необходимы пакеты System.Data.SQLite, NHibernate, NHibernate.Mapping.Attributes):
+

using System;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Mapping.Attributes;
using NHibernate.Tool.hbm2ddl;

namespace NhSQLiteTest
{
    [Class]
    [Serializable]
    public class Product
    {
        [Id(0, Name = "Id", Column = "Id", TypeType = typeof (int))]
        [Generator(0, Class = "identity")]
        public virtual int Id { get; set; }

        [Property]
        public virtual string Name { get; set; }
    }

    internal class Program
    {
        private static void Main()
        {
            using (var uow = new UnitOfWorkFactory().Create())
            {
                var productRepo = new Repository<Product>(uow);
                productRepo.SaveOrUpdate(new Product {Name = "TestRepo"});
            }
            Console.WriteLine("Success!");
            Console.ReadLine();
        }
    }

    public interface IUnitOfWorkFactory
    {
        IUnitOfWork Create();
    }

    public class UnitOfWorkFactory : IUnitOfWorkFactory
    {
        private ISessionFactory _sessionFactory;

        public ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    BuildSessionFactory();
                }
                return _sessionFactory;
            }
        }

        public IUnitOfWork Create()
        {
            return new UnitOfWork(SessionFactory.OpenSession());
        }

        private void BuildSessionFactory()
        {
            var config = new Configuration();

            config.Configure();
            config.AddAssembly(typeof (Product).Assembly);
            HbmSerializer.Default.Validate = true;
            var stream = HbmSerializer.Default.Serialize(typeof (Product).Assembly);
            stream.Position = 0;
            config.AddInputStream(stream);

            new SchemaUpdate(config).Execute(false, true);

            _sessionFactory = config.BuildSessionFactory();
            _sessionFactory.OpenSession();
        }
    }

    public interface IUnitOfWork : IDisposable
    {
    }

    internal class UnitOfWork : IUnitOfWork
    {
        public UnitOfWork(ISession session)
        {
            if (session == null) throw new ArgumentNullException(nameof(session));
            Session = session;
        }

        public ISession Session { get; private set; }

        public void Dispose()
        {
            Session.Dispose();
            Session = null;
        }
    }

    public interface IRepository<T> where T : class
    {
        void SaveOrUpdate(T obj);
    }

    public class Repository<T> : IRepository<T> where T : class
    {
        private readonly UnitOfWork _uow;

        public Repository(IUnitOfWork uow)
        {
            if (uow == null) throw new ArgumentNullException(nameof(uow));
            _uow = uow as UnitOfWork;
            if (_uow == null)
            {
                throw new ArgumentException("Этот репозиторий принимает только единицу работы NHibernate");
            }
        }

        private ISession Session
        {
            get { return _uow.Session; }
        }

        public void SaveOrUpdate(T obj)
        {
            Session.SaveOrUpdate(obj);
        }
    }
}

Ответ: Нахлобуч, buser, hVostt

Спасибо за интересный диалог, внимательно читаю и вникаю) В особенности спасибо hVostt за подробные ответы
Вопрос: Мапирование коллекции сущностей с общим предком в NHibernate

Доброго всем времени!
Смысл вопроса таков - есть сущности: Employee, Boss, Department, IPerson. Один Department хранит несколько Employee и 1-го Boss-а.
Employee и Boss расширяют IPerson:
    public interface IPerson
    {
        int Id { get; set; }
        string Fio { get; set; }
        int Age { get; set; } 
    }

    public class Employee : IPerson
    {
        public virtual int Id { get; set; }
        public virtual string JobTitle { get; set; }
        public virtual string Fio { get; set; }
        public virtual int Age { get; set; }
    }

    public class Boss : IPerson
    {
        public virtual int Id { get; set; }
        public virtual string Fio { get; set; }
        public virtual int Age { get; set; }
        public virtual int EmployeesAmount { get; set; }
    }

    public class Department : IEntity
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual IList<IPerson> Employees { get; set; }
    }


Хочу, чтобы NHibernate при выполнении следующего кода:
            Employee ivan = new Employee() { Fio = "Иван Иванович", Age = 34, JobTitle = "Engeneer"};
            Employee petr = new Employee() { Fio = "Петр Петрович", Age = 28, JobTitle = "Engeneer" };
            Employee sidor = new Employee() { Fio = "Сидор Сидорович", Age = 27, JobTitle = "Engeneer" };
            Boss fedor = new Boss() { Fio = "Федор Федорович", Age = 60, EmployeesAmount = 10 };

            Department devDep = new Department
            {
                Name = "Программирование",
                Employees = new List<IPerson> { ivan, petr, sidor, fedor }
            };
            
            UnitOfWork unitOfWork = new UnitOfWork(true);
            unitOfWork.DepartmentRepository.Add(devDep);
            unitOfWork.Save();

NHibernate каким-то "неведомо-волшебным" образом смапил так, чтобы по дженерелизированному списку сотрудников создались таблицы.
Возможно иметь такой список с общим интерфейсом и разными классами объектов в нем и при этом, чтобы ORM через рефлексию, что ли, смог их отмапить?

Привожу пример мапировок:
Employee.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="NHibernateTest"
                   namespace="NHibernateTest.Infrastructure.Domain">
  <class name="NHibernateTest.Infrastructure.Domain.Employee" table="Employee" lazy="true">
    <id name="Id" column="Id" type="Int32">
      <generator class="identity" />
    </id>
    <property name="Fio" not-null="false"/>
    <property name="Age" not-null="false"/>
    <property name="JobTitle" not-null="false"/>
  </class>
</hibernate-mapping>


Boss.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="NHibernateTest"
                   namespace="NHibernateTest.Infrastructure.Domain">
  <class name="NHibernateTest.Infrastructure.Domain.Boss" table="Boss" lazy="true">
    <id name="Id" column="Id" type="Int32">
      <generator class="identity" />
    </id>
    <property name="Fio" not-null="false"/>
    <property name="Age" not-null="false"/>
    <property name="EmployeesAmount" not-null="false"/>
  </class>
</hibernate-mapping>


Department.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="NHibernateTest"
                   namespace="NHibernateTest.Infrastructure.Domain">
  <class name="NHibernateTest.Infrastructure.Domain.Department" table="Department" lazy="true">
    <id name="Id" column="Id" type="Int32">
      <generator class="identity" />
    </id>
    <property name="Name" not-null="false"/>
    <list name="Persons" table="DepartmentsAndEmployees" cascade="all">
      <key column="DepartmentId"/>
      <index column="Position"/>
      <many-to-many column="EmployeeId" class="NHibernateTest.Infrastructure.Domain.Employee"/>
    </list>
  </class>
</hibernate-mapping>


В последнем файле мапятся сущности Employee. Я не знаю, как сделать еще и для Boss. Как сдеать это самое "наследование" для сущностей?
Ответ:
kmaw
может это поможет



да, спасибо, как раз это и помогло!)