1

I have two simple classes named User and Role in a .Net Web Api project.

The User class is:

public class User
{
    public virtual int Id { get; set; }
    public virtual int RoleId { get; set; }
    public virtual string Name { get; set; }
    public virtual Role Role{ get; set; }

    public User() { }
}

And the Role class is:

public class Role
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }

    public Role() { }
}

The mappings using fluent are:

User:

public UserMap()
{
    Table("plc_users");
    Id(x => x.Id).Column("usr_id");
    Map(x => x.RoleId).Column("rol_id");
    Map(x => x.Name).Column("usr_name");
    References(x => x.Role).Column("rol_id");
}

Role:

public RoleMap()
{
    Table("plc_roles");
    Id(x => x.Id).Column("rol_id");
    Map(x => x.Name).Column("rol_name");
}

This is a unilateral relationship between User and Role. A User has a Role. Although a Role can be present in many Users, in this case, is not interesting to represent this in the Role class.

When I fetch a user from the database, the property "Role" is getting the wrong value. It should be:

{
    "Id" : "2",
    "RoleId" : "1",
    "Name" : "Any",
    "Role": {
        "Id": "1",
        "Name" : "Any"
    }
}

But it's getting:

{
    "Id" : "2",
    "RoleId" : "1",
    "Name" : "Any",
    "Role": {
        "__interceptor": {
              "persistentClass": "NameSpaceForClass, , Version=1.0.0.0 [...]
              "getIdentifierMethod": {
        [...]
      },
}

Observing the console for the SQL commands executed by NHibernate, the command for retrieving the role record is not been called.

So, what Am I missing here? Why the class Role is not been fetched properly according to it's domain definition?

UPDATE:

Thanks to the Radim Köhler answer, I realized that the problem wasn't with Fluent NHibernate, but with the "lazyloading serialization proxy hell".

Following his tips, I've found two new errors:

The first:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'

And the inner:

Could not initialize proxy - no Session.

I'm using a session per action scope which means that the session is started at the begining of the action and closed at the end. From that, I started to try several ways to understand why the session was closing before the Json serialization. Lots of configurations later, I noticed that while in debug mode everything worked fine. And that was weird.

Anyway, I wasn't getting anywhere so I decided to turn off the lazyload mode, like this:

References(x => x.Role).Column("rol_id").ReadOnly().Not.LazyLoad();

This is not the solution. But solves the problem while I'm stuck in finding out why the session works only in debug mode.

dvc.junior
  • 332
  • 6
  • 16

2 Answers2

0

Check these

and following them, introduce your own contract resolver

public class NHibernateContractResolver : DefaultContractResolver
{
  protected override JsonContract CreateContract(Type objectType)
  {
      if (typeof(NHibernate.Proxy.INHibernateProxy).IsAssignableFrom(objectType))
          return base.CreateContract(objectType.BaseType);
      else
          return base.CreateContract(objectType);
  }
}

The trick is... we use BaseType, which is the way how to get from PROXY trap

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Thank you very much! I did some more debugging and I realized that the issue wasn't with Fluent NHibernate at all. But, like you said, with the "lazyloading serialization proxy hell". That leaded me to others problems. They are described in the "Update" of this question. – dvc.junior Nov 15 '16 at 19:33
0

Well, after some refactoring, I came up with a solution.

Let's recap.

I thought that the problem was with the NHibernate Mapings, but I was wrong, they're great, working just fine. The real problem was in the JSON serialization of a proxy object within a collection provided by the NHibernate Mapings.

One of the solutions was to create a custom contract resolver to teach NHibernate to treat child objects like their base class. That really works, but has lead me to another problem, this time to a "no session bound" kind of problem.

After some struggle, and some thinking, I've choose to change the architecture of my Web Api solution by creating a new layer to serve as data transfer. So instead of sending the Entity to the browser, I'm just sending the equivalent DTO (Data Transfer Object).

To do the mapping between the Entity and it's DTO equivalent, I'm using AutoMapper. With this approach, when the JSON serialization occurs, the object will be with all of it's properties set and no longer will depend on the NHibernate proxy objects.

In terms of code, what I did was:

Config AutoMapper:

Mapper.Initialize(cfg => cfg.CreateMap<User, UserDto>());
Mapper.Initialize(cfg => cfg.CreateMap<Role, RoleDto>());

Create the DTOs:

public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public RoleDto Role{ get; set; }
}

public class RoleDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Do the parse:

IList<RoleDto> dtoList = Mapper.Map<RoleDto>(listOfUsers);

That's it. No more troubles with JSON serialization.

dvc.junior
  • 332
  • 6
  • 16