Как создать прокси-объект NHibernate с некоторыми инициализированными полями (отличными от Id)?

#nhibernate #proxy-classes

#nhibernate #прокси-классы

Вопрос:

Я хочу создать прокси-объект, аналогичный тому, что ISession.Загрузка возвращается, но с инициализированными некоторыми полями. Для других свойств, при обращении к которым прокси-сервер извлекает весь объект из базы данных. Рассмотрим следующий пример:

 public class User
{
    protected User() {

    }

    public User(int id, string username, string email) {
        // ... 
    }

    // initialize the following fields from other datasources
    public virtual int Id { get; set; }
    public virtual string UserName { get; set; }
    public virtual string Email { get; set; }

    // the rest of fields when accessed will trigger a select by id in the database
    public virtual string Field1 { get; set; }
    public virtual string Field2 { get; set; }
    public virtual DateTime Field3 { get; set; }
    public virtual ISet<Comment> Comments { get; set; }
}
  

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

Редактировать: Цель этого — иметь некоторые свойства проекции из объекта, которые могут быть запрошены в другом месте (скажем,. индекс lucene) и избегать вызовов базы данных. Тогда вместо того, чтобы переносить эти поля в пользовательский класс компонента, содержащий только это подмножество свойств, я хочу использовать прокси-объект напрямую, чтобы при необходимости я мог загружать остальные поля. В лучшем случае я бы вообще не обращался к базе данных, но в некоторых крайних случаях я бы хотел получить доступ и к другим полям. Влияние проблемы ВЫБОРА N 1 может быть значительно уменьшено с помощью пакетной обработки. Гипотетическая версия кода, которую я хочу использовать, будет:

         // create User object proxy with some fields initialized
        var user = Session.Load<User>(5, new { UserName = "admin", Email = "admin@company.com" });
        Console.WriteLine(user.Id); // doesn't hit the database
        Console.WriteLine(user.UserName); // doesn't hit the database
        Console.WriteLine(user.FullName); // doesn't hit the database
        if (somecondition) {
            Console.WriteLine(user.Field1); // fetches all other fields 
        }
  

Ответ №1:

Вы можете указать нетерпеливую выборку внутри запроса, чтобы фактически получить необходимые ассоциации. Это может быть сделано по-разному в зависимости от того, какой стиль запроса (критерии, Hql или LINQto NH ) вы используете. Но ключ меняет режим выборки.

Ответ №2:

для свойств, не входящих в коллекцию, я бы не стал этого делать;
стоимость предварительной выборки их из базы данных при загрузке вашего объекта (обычно) настолько мала, что я бы даже не стал беспокоиться.
для свойств коллекции просто отметьте стратегию выборки коллекции как 'lazy=true' .

Единственный случай, когда я бы подумал о том, чтобы сделать что-то подобное, — это когда у меня есть очень большое количество свойств, которые мне не нужны (в вашем примере — скажем, Field1 ..Поле 20).
В этом случае я бы либо:
1. Определил эти свойства вместе как компонент, либо
2. создал DTO для извлечения только подмножества свойств вашего объекта.

Комментарии:

1. Вы правы насчет большого количества свойств, то, что я ищу, — это небольшая проекция полей из класса entity (2-4 поля), но без использования псевдонима obeantransformer anonymous classes для проекции, потому что я мог бы запрашивать не к базе данных. И возможность загружать другие поля, если это необходимо, в некоторых крайних случаях.

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

Ответ №3:

указание lazy = «true» (или нет.Может помочь LazyLoad() для свободного NHib) в свойствах Field1 , Field2 , Field3 , Comments сопоставлениях, хотя я не уверен в проблеме выбора N 1.

другой способ — указать lazy = «false» для UserName , Email