Как создать прокси-объект NHibernate с некоторыми инициализированными полями (кроме Id)? - PullRequest
3 голосов
/ 14 июня 2011

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

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, UserName, Email хорошо известны в моем случае, поэтому я мог бы создать прокси-сервер объекта, содержащий эти поля, а для других оставить поведение прокси-сервера по умолчанию.В дополнение к выбрасыванию исключения, если этот идентификатор не найден в базе данных, я мог бы выдать исключение, если предварительно инициализированные поля не совпадают или перезаписывают их молча.Я использую NHibernate.ByteCode.Castle для прокси-фабрик.

Редактировать: Цель этого состоит в том, чтобы иметь возможность иметь некоторые свойства проекции от объекта, к которым можно обращаться в другом месте (например, с индексом lucene), и избегать вызовов базы данных.Затем вместо того, чтобы оборачивать эти поля в пользовательский класс компонентов, содержащий только эти подмножества свойств, я хочу использовать прокси-объект напрямую, чтобы при необходимости я мог загрузить остальные поля.В лучшем случае я бы вообще не попал в базу данных, но в некоторых угловых случаях мне бы хотелось получить доступ и к другим полям.Влияние проблемы SELECT 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 
        }

Ответы [ 3 ]

0 голосов
/ 14 июня 2011

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

еще один способ - указать lazy = "false" для UserName, Email

0 голосов
/ 14 июня 2011

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

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

0 голосов
/ 14 июня 2011

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

...