Question

I'm working on a Web API 2.0 project and suspect I'm doing something monumentally wrong with a ModelFactory class.

I'm attempting to implement factory 'Create' methods for constructing and returning sanitised models of my data layer entities. I'm hitting difficulties when I put together the Create method for an entity (Foo) that's the principal of a one-to-many relationship with a set of dependent entities (Bar). I would like the consuming client application(s) to be able to use the returned model object to navigate from Foo to its collection of Bars, and from a given Bar to its parent Foo. Both sides of this relationship would appear to require model creation as follows:

public class ModelFactory
{
    public FooModel Create(Foo foo)
    {
        return new FooModel()
        {
            FooProperty1 = foo.FooProperty1,
            FooProperty2 = foo.FooProperty2,
            ...,
            Bars = foo.Bars.Select(b => Create(b)).ToList()
        };
    }

    public BarModel Create(Bar bar)
    {
        return new BarModel()
        {
            BarProperty1 = bar.Property1,
            BarProperty2 = bar.Property2,
            ...,
            Foo = Create(bar.Foo)
        };
    }
}

Unfortunately this results in an infinite loop with Foo creating Bars, which create subsequent Foos, and so on and so on. I've seen a couple of implementations where the many/dependent side of the relationship is returned without a reference to its parent object, which eliminates the problem, but I'd like to retain that linkage if possible.

Given that this is such a vanilla arrangement, I suspect that I'm completely missing the point somewhere. What's the right way to put this together?

Was it helpful?

Solution

Do you ever create a BarModel without a parent FooModel? The first thing that comes to my mind is to simply require passing the parent FooModel into the BarModel Create method:

public class ModelFactory
{
    public FooModel Create(Foo foo)
    {
        var fooModel = new FooModel()
        { ... };

        // pass this model instance to the Create method
        fooModel.Bars = foo.Bars
              .Select(b => Create(b, fooModel))
              .ToList();

        return fooModel;
    }

    // how about making this private?
    // can a Bar exist without a Foo parent?
    private BarModel Create(Bar bar, FooModel parentModel)
    {
        return new BarModel()
        {
            // we don't create a new model here
            Foo = parentModel
        };
    }
}

On a side note, usual direction of the DAL-Entities dependency is to declare your entities (FooModel, BarModel) in your domain model, and have the DAL know about them and return instances of these actual entities. You can have data-specific DAOs (Foo, Bar) if you need them for the db access to work properly (although they are rarely needed if you're using an ORM framework), but they should be internal to the data layer, without the need to do these mappings inside your business logic.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top