views:

42

answers:

1

After lots of reading about serialization, I've decided to try to create DTOs. After more reading, I decided to use AutoMapper.

What I would like to do is transform the parent (easy enough) and transform the entity properties if they've been initialized, which I've done with ValueResolvers like below (I may try to make it generic once I get it fully working). This part works.

public class OrderItemResolver : ValueResolver<Order, OrderItem>
{
    protected override OrderItem ResolveCore(Order source)
    {
        // could also use NHibernateUtil.IsInitialized(source.OrderItem)
        if (source.OrderItem is NHibernate.Proxy.INHibernateProxy)
            return null;
        else
            return source.OrderItem;
        }
    }
}

When I transform the DTO back to an entity, for the entities that weren't initialized, I want to create a proxy so that if the entity wants to access it, it can. However, I can't figure out how to create a proxy. I'm using Castle if that's relevant.

I've tried a bunch of things with no luck. The below code is a mess, mainly because I've been trying things at random without knowing what I should be doing. Anybody have any suggestions?

public class OrderItemDTOResolver : ValueResolver<OrderDTO, OrderItem>
{
    protected override OrderItem ResolveCore(OrderDTO source)
    {
        if (source.OrderItem == null)
        {
            //OrderItem OrderItem = new ProxyGenerator().CreateClassProxy<OrderItem>(); // Castle.Core.Interceptor.

            //OrderItem OrderItem = new ProxyGenerator().CreateClassProxy<OrderItem>();
            //OrderItem.Id = source.OrderItemId;

            //OrderItem OrderItem = new OrderItem();
            //var proxy = new OrderItem() as INHibernateProxy;
            //var proxy = OrderItem as INHibernateProxy;
            //return (OrderItem)proxy.HibernateLazyInitializer
            //ILazyInitializer proxy = new LazyInitializer("OrderItem", OrderItem, source.OrderItemId, null, null, null, null);
            //return (OrderItem)proxy;
            //return (OrderItem)proxy.HibernateLazyInitializer.GetImplementation();

            //return OrderItem;

            IProxyTargetAccessor proxy = new Castle.Core.Interceptor.

            var initializer = new LazyInitializer("OrderItem", typeof(OrderItem), source.OrderItemId, null, null, null, null);
            //var proxyFactory = new SerializableProxyFactory{Interfaces = Interfaces, TargetSource = initializer, ProxyTargetType = IsClassProxy};

            //proxyFactory.AddAdvice(initializer);
            //object proxyInstance = proxyFactory.GetProxy();
            //return (INHibernateProxy) proxyInstance;
            return null;


            //OrderItem.Id = source.OrderItemId;
            //return OrderItem;
        }

        else
            return OrderItemDTO.Unmap(source.OrderItem);
    }
}

Thanks, Eric

Maybe I over complicated it. This seems to work. Anybody see any issues with it?

public class OrderItemDTOResolver : ValueResolver<OrderDTO, OrderItem>
{
    protected override OrderItem ResolveCore(OrderDTO source)
    {
        if (source.OrderItem == null)
            return NHibernateSessionManager.Instance.Session.GetISession().Load<OrderItem>(source.AgencyId);

        else
            return OrderItemDTO.Unmap(source.OrderItem);
    }
}
A: 

This may be one of those cases where the answer is "don't", or at least "you probably shouldn't". If you're mapping DTOs into NHibernate mapped objects directly you're not really using the mapped objects as domain objects, just as a fancy way to push data in and out of the database. This of course may be all you're after but having done this myself in the past I've found that it's problematic trying to use the same DTO data format in both directions. If you're going cross-process you've turned the service into a (difficult to maintain) CRUD layer. If you're in the same process you're doing unnecessary data shuffling with DTOs.

Sending DTOs out is fine, but consider projecting the data into a format more closely aligned with what the client actually needs. What you get back is better expressed in specific DTOs that express only the data needed to perform the actual action (Command objects, essentially). With a few automatic properties they're trivial to construct. You can then have a business method that performs the necessary action with only the necessary information, and that in a format suited to the action being performed. My primary use of AutoMapper (which does rock) these days is to translate incoming DTOs into types that domain methods can consume.

Also, public setters on mapped objects are undesirable because they allow the object to be manipulated by any code without any validation. This means any modification to them can leave them in an invalid state.

If you don't really care about the above (and it's not always applicable) the way you load individual instances does leave you open do doing many individual database loads which is a potential performance issue.

AbstractCode
I'm not a huge fan of this approach myself, so I definitely understand the "don't" response.I want to do this in a limited scenario. The reason I'm trying to do this is I'm working on a classic ASP.NET site. The products I'm selling are very customizable; selecting some options, enable other options, all of which dictate pricing. If I populate my entity, I can call a function to price it. The pricing goes to the database to get dynamic pricing tables based on the options. Currently I'm rebuilding the entity on each post/callback which is tedious. I was hoping for something more automatic.
Eric
That does make things more problematic. Some possible options:- Use Query Objects that encapsulate how to search for pricing. I do this with objects that return DetachedCriteria so that my controllers (in MVC) can add paging, sorting etc. You could make a base class that can then be customised for each circumstance.- Precalculate the pricing. Of course you say you have many options so this may be a very large data set. Might be something a NoSQL DB could handle though.I'd still be strongly opposed to the 1:1 DTO and mapped object arrangement. It's just asking for trouble.
AbstractCode
This is a system I inherited which can be a bit archaic at times. Pricing spans about 10 different tables and requires extensive data access. We've got it working with rebuilding the entity based on the viewstate, but it's ugly.
Eric