NHibernate.Linq, WCF RIA Services, странная ошибка - PullRequest
3 голосов
/ 26 февраля 2010

У меня настроен проект бизнес-приложения Silverlight с этими кодами.

У меня есть этот класс домена:

public class BaseDomain
{
    public virtual Guid Id { get; set; }
    public virtual DateTime CreatedOn { get; set; }
}

public class Sector : BaseDomain
{
    public virtual string Code { get; set; }
    public virtual string Name { get; set; }
}

Сопоставление объектов домена установлено и работает нормально.

У меня есть этот класс DTO:

public class SectorDto : BaseDto
{
    [Key]
    public virtual Guid Id { get; set; }
    public virtual DateTime CreatedOn { get; set; }
    public virtual string Code { get; set; }
    public virtual string Name { get; set; }

    public SectorDto()
    {
    }

    public SectorDto(Sector d)
    {
        Id = d.Id;
        CreatedOn = d.CreatedOn;
        Code = d.Code;
        Name = d.Name;
    }
}

DTO используется для выравнивания объекта и предотвращения ненужных связей при сериализации и передаче по проводу.

Тогда у меня есть этот RIA DomainService (есть несколько вариантов метода GetSectors (), я объясню позже):

[EnableClientAccess]
public class OrganizationService : BaseDomainService
{
    public IQueryable<SectorDto> GetSectors1()
    {
        return GetSession().Linq<Sector>()
               .Select(x => Mapper.Map<Sector, SectorDto>(x));
    }

    public IQueryable<SectorDto> GetSectors2()
    {
        return GetSession().Linq<Sector>().ToList()
               .Select(x => new SectorDto(x)).AsQueryable();
    }

    public IQueryable<SectorDto> GetSectors3()
    {
        return GetSession().Linq<Sector>().Select(x => new SectorDto(x));
    }

    public IQueryable<SectorDto> GetSectors4()
    {
        return GetSession().Linq<Sector>().Select(x => new SectorDto() { 
            Id = x.Id, CreatedOn = x.CreatedOn, Name = x.Name, Code = x.Code });
    }
}

BaseDomainService - это просто родительский класс, обеспечивающий обработку сеанса NHibernate. Я настроил сеанс на каждый веб-запрос.

Затем я подключаю сервис к DataGrid (Silverlight Toolkit) на странице XAML:

var ctx = new App.Web.Services.OrganizationContext();
SectorGrid.ItemsSource = ctx.SectorDtos;
ctx.Load(s.GetSectors1Query());

При вызове различных методов я получил следующие результаты:

  1. Метод GetSectors1 () создает исключение "Не удалось выполнить операцию загрузки для запроса 'GetSectors1'. Невозможно привести объект типа NHibernate.Linq.Expressions.EntityExpression 'к типу' NHibernate .Linq.Expressions.CollectionAccessExpression»". .

    Это лучший способ, которого я пытаюсь достичь. Я хочу использовать библиотеку AutoMapper для автоматического сопоставления класса домена с DTO. Я совершенно уверен, что проблема не в AutoMapper, поскольку я также получаю сообщение об ошибке, если вызываю метод из анонимного метода, переданного в Select, например. GetSession().Linq<Sector>().Select(x => CustomMap(x)).

  2. Метод GetSectors2 () правильно отображает данные в сетке, но это лишает цели использования IQueryable, вызов не будет обрабатываться лениво.

  3. Метод GetSectors3 () извлекает данные, но только Id и CreatedOn, которые находятся в родительском классе BaseDomain. Код и Имя не имеют значения.

  4. Метод GetSectors4 () извлекает данные правильно и лениво оценивается, но я не хочу вручную каждый раз сопоставлять свой домен с DTO, как это!

Так что же дает? Результаты настолько далеки, чем я ожидал! Есть идеи, как заставить это работать? Любой совет?

Я ценю любую помощь, я почти потерян. Большое спасибо.

Ответы [ 3 ]

0 голосов
/ 12 октября 2010

Хорошо, вы можете упростить процесс выделения выражения select:

Например:

public Expression<Func<Sector,SectorDto>> EntityToDto = 
        x => new SectorDto
            {
                Id = d.Id;
                CreatedOn = d.CreatedOn;
                Code = d.Code;
                Name = d.Name;
            };

А затем используйте его как:

public IQueryable<SectorDto> GetSectors4()
    {
        return GetSession().Linq<Sector>().Select(EntityToDto);
    }

Вы можете определить этот метод внутри Dto. Кстати, в основном это называется моделью представления при использовании ее внутри сервисов RIA, просто для целей поиска :). Я еще не пробовал (я нашел ваш вопрос, когда искал те же ответы, что и вы, но ваш вопрос заставил меня задуматься), но я не понимаю, почему это не сработает. Кроме того, я использую множество процессов генерации кода, поэтому я просто сгенерирую эту часть. Надеюсь, это поможет!

0 голосов
/ 05 апреля 2011

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

Nhibernate пытается преобразовать ваш оператор LINQ с вашим выбором в SQL, когда вы вызываете .ToList (). Он не может преобразовать ваш код автомата в SQL (который находится в выбранном статусе). Вот почему вы должны сначала выбрать объект из базы данных, затем вызвать .ToList () для выполнения SQL, а затем снова просмотреть список и отобразить его.

0 голосов
/ 23 сентября 2010

GetSession (). Linq () .ToList () .Select (x => CustomMap (x))

См. Также http://www.mail-archive.com/nhusers@googlegroups.com/msg12003.html

...