views:

146

answers:

2

I am trying to refactor some Entity Framework code where I have a Products entity and related entities for the Product's series, family, brand, etc. The series, family, and brand entities all have the same basic structure with an Id and Text property.

The two methods below are very similar and should be able to be refactored to a single method, but I'm not sure how to dynamically pass in which entity I'm querying from. In this case I need to be able to pass in db.ProductFamilies, or db.ProductSeriesSet. Any ideas how to make these 2 become 1?

Thanks!

    public DTOs.ProductCollection GetFamily(int id)
    {
        using (Entities db = new Entities())
        {
            var fam = (from collection in db.ProductFamilies.Include("Product")
                        .Include("Product.Stuff1")
                        .Include("Product.Stuff2")
                       where collection.Id == id
                       select collection).FirstOrDefault();
            return ProductCollectionEFToProductCollectionDTO(fam, true);
        }
    }

    public DTOs.ProductCollection GetSeries(int id)
    {
        using (Entities db = new Entities())
        {
            var ser = (from collection in db.ProductSeriesSet.Include("Product")
                        .Include("Product.Stuff1")
                        .Include("Product.Stuff2")
                       where collection.Id == id
                       select collection).FirstOrDefault();
            return ProductCollectionEFToProductCollectionDTO(ser, true);
        }
    }
+2  A: 

If db.ProductFamilies and db.ProductSeriesSet are inherited from the same base class, then when you use ProductCollectionEFToProductCollectionDTO(BaseClass obj, bool value );

Or think about Generic type.

Those are two basic approaches.

J.W.
How to handle the difference spotted in the from clause, where you query from ProductSeriesSet OR ProductFamilies?
Romain Verdier
I didn't notice that, yes, yours is better than mine.
J.W.
+5  A: 

You could use a Func<T, TResult> to delegate the selection of the good entity collection to the caller:

public DTOs.ProductCollection Get(int id, Func<Entities, XXX> selector)
{
    using (Entities db = new Entities())
    {
        var result = (from collection in selector(db).Include("Product")
                    .Include("Product.Stuff1")
                    .Include("Product.Stuff2")
                   where collection.Id == id
                   select collection).FirstOrDefault();
        return ProductCollectionEFToProductCollectionDTO(result, true);
    }
}

Here, XXX is of type of db.ProductFamilies and db.ProductSeriesSet.

You can then call it like that:

Get(42, db => db.ProductFamilies);
Get(12, db => db.ProductSeriesSet);

Does it work?

Romain Verdier
Almost there. The issue I'm having is that ProductFamilies and ProductSeriesSet (XXX) have no common base class so I don't have a type to replace XXX with. What I tried doing was adding a ProductCollection interface that they both implement. Continued in next comment...
EricAppel
By having the common interface I could implement the method but when calling had to do the followingGetProductCollection(id, db => (ObjectQuery<ProductCollection>)db.ProductFamilies.Cast<ProductCollection>());Continued ...
EricAppel
Because of the cast I get "LINQ to Entities only supports casting Entity Data Model primitive types" at runtime. I don't see how I can get a common base type to work with all of these entities. Each entity pulls their common fields from a different table. How can I generically work with entities?
EricAppel