views:

464

answers:

2

Hi all. I have a Silverlight Business Application project set up, with these codes.

I have this domain class:

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; }
}

The domain objects mapping has been set up and working fine.

The I have this DTO class:

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 is used to flatten the object and make sure no unnecessary relations from being serialized and transfered over the wire.

Then I have this RIA DomainService (there are several variations of the GetSectors() method, I'll explain later):

[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 is just a parent class that provides handling for NHibernate session. I set the session to live per web request.

Then I hook up the service to a DataGrid (Silverlight Toolkit) in a XAML page:

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

When calling the various methods, I got these results:

  1. Method GetSectors1() produce an exception "Load operation failed for query 'GetSectors1'. Unable to cast object of type NHibernate.Linq.Expressions.EntityExpression' to type 'NHibernate.Linq.Expressions.CollectionAccessExpression'.".

    This is the best way that I'm trying to achive. I want to use the AutoMapper library to automatically map the domain class to the DTO. I'm quite positive that the problem is not from the AutoMapper since I also get the error if I call a method from inside the anonymous method passed into Select, eg. GetSession().Linq<Sector>().Select(x => CustomMap(x)).

  2. Method GetSectors2() displays the data correctly in the grid, but this defeats the purpose of using IQueryable, the call would not be lazy evaluated.

  3. Method GetSectors3() fetches the data, but only the Id and CreatedOn which is in the parent class BaseDomain. The Code and Name are both null.

  4. Method GetSectors4() fetches the data correctly and lazily evaluated, but I don't want to manually map my domain to DTO every time like this!

So what gives? The results are so far away than what I expected! Any idea on how to make this work? Any advice?

I appreciate any help, I'm nearly lost. Thank you very much.

A: 

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

See also http://www.mail-archive.com/[email protected]/msg12003.html

Joerg
A: 

Well, one thing you can do to make things easier is separate the select expression:

For instance:

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

And then use it as:

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

You can define that method inside the Dto. Btw, it's mostly called presentation model when using it inside RIA services, just for search purposes:). I haven't tried this yet (i found your question when searching for same answers as you do, but your question got me thinking) but i don't see why it wouldn't work. Plus i'm using plenty of code generation in the process, so i just generate this part. Hope this helps!

Bruno Altinet