1
votes

I have the following data model

public class Profile : Entity
{
    public virtual string Name { get; set; }
    public virtual int Sequence { get; set; }
    public virtual string Description { get; set; }
    public virtual IList<MapService> MapServices { get; set; }
}

public class MapService : Entity
{
    public virtual string Name { get; set; }
    public virtual string Url { get; set; }
    public virtual int MaximumResolution { get; set; }
}

As you can see , a profile has many MapService(s).

And the relation is many to many.

I am building an ASP.NET Web API rest service that return profile data. I have two calls, one to return all the profiles, and the second filtered by ID, with the following URL

http://myapp/api/profiles
http://myapp/api/profiles/:id

I am using NHibernate for data access in the API Controller.

the Web API controller looks like this

public class ProfilesController : ApiController
{
    public ProfilesController()
    {
    }

    public IEnumerator<Profile> GetAllProfiles()
    {
        using (Session = .. create nhibernate session )
        {
            return Session.Query<Profile>().GetEnumerator();
        }
    }
}

When I return the whole list, I don't want the details of the MapService(s), just the Name and Id

so, I thought I will do lazy loading. So, I configured the nhibernate mapping using fluent nhibernate as follows

public class ProfileMapping : ClassMap<Profile>
{
    public ProfileMapping()
    {
        Table("PROFILE");
        Id(x => x.Id, "OBJECT_ID");
        Map(x => x.Name, "PROFILE_NAME");
        Map(x => x.Sequence, "SEQUENCE_NO");
        Map(x => x.Description, "DESCR");
        HasManyToMany<MapService>(x => x.MapServices).LazyLoad().
            Table("PROFILE_MAP_SERVICE").ParentKeyColumn("PROFILE_ID").ChildKeyColumn("MAP_SERVICE_ID");
    }
}

I thought by doing this, I will return only the profile data without the details of MapService List

But when I call the rest service to return the whole data like this

http://myapp/api/profiles

I get this error

"Message":"An error has occurred.","ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json

"Message":"An error has occurred.","ExceptionMessage":"Initializing[Domain.Profile#2]-failed to lazily initialize a collection of role: Domain.Profile.MapServices, no session or session was closed","ExceptionType":"NHibernate.LazyInitializationException","StackTrace":"

It seems that the nhibernate is returning the list of profiles without mapservices, and close the session.

But them somehow the web api service is trying to access the list of map service during serialization.

how to tell the web api service to ignore the map service list?

1

1 Answers

5
votes

The simple approach here would be to introduce the DTO object:

public class ProfileDto
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string Sequence { get; set; } // or Guid...
    public virtual string Description { get; set; }
    ... // if more needed
}

and then adjust the API Controller method

public IEnumerable<ProfileDto> GetAllProfiles()
{
    using (var session = ...)
    {
        return session.Query<Profile>()
            .Select(entity => new ProfileDto
            {
                Id = entity.ID,
                Name = entity.Name,
                Sequence = entity.Sequence,
                Description = entity.Description,
            })
            .ToList();
    }
}

The most important here is the call .ToList() which will assure, that all the loads from DB server are done during the session life time (using clause). Automapper maybe could be next step to make it more easy (less code)...