NHibernate, привязка данных к DataGridView, отложенная загрузка и управление сессиями - нужен совет - PullRequest
2 голосов
/ 02 апреля 2010

Моя основная форма приложения (WinForms) имеет DataGridView, который использует DataBinding и Fluent NHibernate для отображения данных из базы данных SQLite. Эта форма открыта на все время работы приложения.

По соображениям производительности я установил соглашение DefaultLazy.Always () для всех обращений к БД.

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

Другая часть приложения может работать в фоновом режиме и сохранять в БД. В настоящее время (после значительной борьбы) мой подход заключается в вызове MainSession.Disconnect (), создании одноразового сеанса для каждого сохранения и MainSession.Reconnect () после завершения сохранения. В противном случае SQLite выдаст исключение «Файл базы данных заблокирован».

Пока что это работает хорошо, но прошлый опыт заставлял меня нервничать из-за того, что долгое время оставался открытым для сеанса (у меня возникли проблемы с производительностью, когда я пытался использовать один сеанс для сохранений и загрузок - кеш) заполнил и завалил все - см. Фиксация ОЧЕНЬ медленная в моем проекте NHibernate / SQLite ).

Итак, мой вопрос - это хороший подход или я смотрю на проблемы в будущем?

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

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

Редактировать

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

Кажется, что в эти дни на SO появляется гораздо больше пользователей NH - кто-нибудь хочет предложить лучший подход?

Ответы [ 2 ]

1 голос
/ 03 апреля 2010

Да, это снова я. ; -)
натыкаясь на ваш новый вопрос, напоминает мне следующее: вы понимали принцип отложенной загрузки или ошибочно принимали загрузку за нумерацию страниц? NHibernate также обеспечивает функциональность для этого.

Если вы просто хотите отобразить некоторые определенные свойства в вашей сетке, которые, конечно, находятся в графе объектов, я думаю, что вы должны получить все данные сразу, используя «извлеченные соединения». Если количество строк данных слишком велико, вы можете подумать о нумерации страниц , насколько я знаю, это также возможно при использовании DataGridView и Binding.
Ленивая загрузка приводит к нескольким вызовам базы данных - в вашем случае я думаю, по крайней мере, один на строку. Похоже, это не самое эффективное решение.
Если вместо этого вы используете пейджинг с FetchType.Join, вы можете избавиться от продолжительного сеанса, и все ваши проблемы должны быть решены. Так как насчет этого?

0 голосов
/ 29 ноября 2011

У меня был проект, в котором была основная сетка для выбора.

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

class MyList : IList<Data>
{
    private int _pagesize = 50;
    private int _session;     // from ctor

    private int _firstresult = int.MinValue;
    private IList<Data> cached;

    public Data this[int index]
    get
    {
        if (!index.Between(_firstresult, _firstresult + cached.Count))
        {
            _firstresult = index;
            GetData();
        }
        if (!index.Between(_firstresult, _firstresult + cached.Count))
            throw new IndexOutOfRangeException();

        return cachedData[index - _firstresult];
    }

    void GetData()
    {
        Session.Clear();

        cached = Session.QueryOver<Data>()
            .Skip(_firstresult)
            .Take(_pagesize)
            .List();
    }
}

Если вам нужна привязка данных, возможно, реализуйте IBindingList

...