0

I am having trouble with the lazy, eager and explicit loading design patterns common in C# ORM libraries, specifically with derived types that have their own collections.

For example, I want to persist the model below:

public abstract class Offer
{
    public int Id { get; set; }
}

public class DiscountOffer : Offer
{
    public float Percent { get; set; }
}

public class ColourOffer : Offer
{
    public List<string> Colours { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = "Unknown";
    public IList<Offer> Offers { get; set; } = new List<Offer>();
}

I can easily map and save this to a database using either Entity Framework or NHibernate, the problem comes when I then want to retrieve a full product from the database and send it over the wire using WCF.

If I have the following product:

new Product
{
    Name = "Chair",
    Offers = new List<Offer>
    {
        new DiscountOffer { Percent = 0.2f },
        new ColourOffer
        {
            Colours = new List<string>
            {
                "Red", "Blue", "Green"
            }
        },
    }
};

If the product is lazy loaded then it is encapsulated in a proxy so that it knows when fetch the sub-collections. This presents a problem as the serialization will fail as the type is not as expected.

I found a few answers to this problem:

  1. Disable lazy loading and eager/explicit load. This works until you meet the the abstract collection. I could find a way to Include/Fetch the ColourOffer.Colours path:

NHibernate:

session.Get<Product>(1).Fetch(p => p.Offers) // If ColourOffer Fetch Colours?

EF:

DbSet<Product> Products { get; set; }

// ...

Products.Include(p => p.Offers) // If ColourOffer Include Colours?
  1. Use DTOs and AutoMapper. I have gathered this is generally a good idea but I run into the same issue of AutoMapper not knowing what to do with the proxy class and so I have to disable lazy loading which takes me back to point 1.

  2. Use a IDataContractSurrogate to load the content on serialization. I tried a couple of the implementations floating around on the web but I could not get any to work. I believe this is because the session was being closed by the point of serialization and so the data for the collection could not be fetched.

I now do not know what to do. I just want to load a full product but I cannot find a solution and it is driving me insane.

maddisoj
  • 576
  • 6
  • 16
  • Did you actually tried with `Include()`? Did you have any issues? – Ingweland Apr 11 '16 at 18:36
  • I am afraid this is not possible. To make it work you have to put all properties you need to single class, and based on manually assigned discriminator map it to Dtos/Domain objects. – Red Apr 11 '16 at 20:22
  • 1
    Probably best option is the solution 2, there are few solutions to the problem see http://stackoverflow.com/questions/11816732/copying-nhibernate-poco-to-dto-without-triggering-lazy-load-or-eager-load – Low Flying Pelican Apr 11 '16 at 23:51

1 Answers1

0

Using Fluent NHibernate, adding the DefaultLazy.Never() convention appears to cause the full object graph to be fetched when requested.

Fluently.Configure()
    // ...
    .Mappings(m => m
        .FluentMappings.AddFromAssemblyOf<MyClass>()
        .Conventions.Add(FluentNHibernate.Conventions.Helpers.DefaultLazy.Never()))
    // ...

This also has the added benefit that I do not have to deal with the proxies not working with WCF.

maddisoj
  • 576
  • 6
  • 16