5
\$\begingroup\$

These two methods do very similar things. Is it possible to condense these somehow? This is using the Entity Framework.

public void ExportSiteData (FLEX_INV_EXP_SITE siteData)
{
    var uniqueSite = from e in _context.FLEX_INV_EXP_SITE
                     where e.SITE_ID == siteData.SITE_ID
                     select e;
    var count = uniqueSite.Count();

    if (count != 0) return;
    _context.FLEX_INV_EXP_SITE.AddObject(siteData);
    _context.SaveChanges();
}

public void ExportAddressData (FLEX_INV_EXP_ADDRESS addressData)
{
    var uniqueSite = from e in _context.FLEX_INV_EXP_ADDRESS
                     where e.SITE_ID == addressData.SITE_ID
                     select e;
    var count = uniqueSite.Count();

    if (count != 0) return;
    _context.FLEX_INV_EXP_ADDRESS.AddObject(addressData);
    _context.SaveChanges();
}
\$\endgroup\$
6
  • \$\begingroup\$ Can you make them both share an interface? - that would be the easiest way (and wouldn't use generics at all). There is also a duck typing library for C# (never looked at it myself though) \$\endgroup\$ Jan 5 '12 at 15:48
  • \$\begingroup\$ I probably could get them to share an interface - I'm not sure how that'd help though, can you provide an explanation? \$\endgroup\$ Jan 5 '12 at 16:46
  • \$\begingroup\$ what type is _context.FLEX_INV_EXP_ADDRESS? \$\endgroup\$
    – J. Holmes
    Jan 5 '12 at 17:53
  • 4
    \$\begingroup\$ +1 because it is interesting how complex the proposed solutions are: Makeing the solution a little more dry by violating the kiss principle :-( \$\endgroup\$
    – k3b
    Jan 5 '12 at 23:39
  • \$\begingroup\$ @k3b - Can't agree more, the idea was to make things simpler \$\endgroup\$ Jan 6 '12 at 8:55
2
\$\begingroup\$

It seems the only two unique things about the blocks of code are the Tables that you are searching/adding to and how the SITE_IDs are obtained (from different types). You could just make your method accept two additional parameters, the table that is being searched and a lambda which selects the SITE_ID. You'll just have to rewrite some expressions.

public static void ExportData<TEntity, TSite>(
    ObjectSet<TEntity> table,
    Expression<Func<TEntity, TSite>> siteIdSelector,
    TEntity data)
    where TEntity : class
{
    var condition = GetCondition(siteIdSelector, data);
    var isInTable = table.Where(condition).Any();
    if (!isInTable)
    {
        table.AddObject(data);
        table.Context.SaveChanges();
    }
}

private static Expression<Func<TEntity, bool>> GetCondition<TEntity, TKey>(
    Expression<Func<TEntity, TKey>> keySelector,
    TEntity data)
    where TEntity : class
{
    var entity = Expression.Parameter(typeof(TEntity), "entity");
    var entityKey = BindParameter(keySelector, entity);
    var dataKey = BindParameter(keySelector, Expression.Constant(data));
    var body = Expression.Equal(entityKey , dataKey);
    return Expression.Lambda<Func<TEntity, bool>>(body, entity);
}

private static Expression BindParameter<TEntity, TKey>(
    Expression<Func<TEntity, TKey>> keySelector,
    Expression entity)
    where TEntity : class
{
    return new SubstitutionVisitor
    {
        OldExpr = keySelector.Parameters.Single(),
        NewExpr = entity,
    }.Visit(keySelector.Body);
}

public class SubstitutionVisitor : ExpressionVisitor
{
    public Expression OldExpr { get; set; }
    public Expression NewExpr { get; set; }

    public override Expression Visit(Expression node)
    {
        return (node == OldExpr) ? NewExpr : base.Visit(node);
    }
}

Then to use it, you could do something like this:

ExportData(_context.FLEX_INV_EXP_SITE, entity => entity.SITE_ID, siteData);
ExportData(_context.FLEX_INV_EXP_ADDRESS, entity => entity.SITE_ID, addressData);
\$\endgroup\$
0
0
\$\begingroup\$

Here is a wildly simplified example, but you could try something like this:

public class EXP_SITE
{
    public int SITE_ID { get; private set; }    
}

public class EXP_ADDRESS
{
    public int SITE_ID { get; private set; }    
}

public class SomeList<T> : List<T>
{
    public void AddObject(object o) { }
}

public class UnknownClass
{
    private SomeList<EXP_ADDRESS> Addresses;
    private SomeList<EXP_SITE> Sites;

    private void ExportGeneric<T>(T item, SomeList<T> list, Func<T, bool> matcher)
    {
        var uniqueSite = from e in list
                         where matcher.Invoke(e) 
                         select e;

        var count = uniqueSite.Count();

        if (count != 0) return;
        list.AddObject(item);
        //save();
    }

    public void ExportSiteData(EXP_SITE site)
    {
        ExportGeneric(site, Sites, s => s.SITE_ID == site.SITE_ID);
    }

    public void ExportAddressData(EXP_ADDRESS addr)
    {
        ExportGeneric(addr, Addresses, a=> a.SITE_ID == addr.SITE_ID);
    }
}

But really, I would probably change ExportGeneric to say:

    private void ExportGeneric<T>(T item, SomeList<T> list, Func<T, bool> matcher)
    {
        if(list.Any(matcher)) return;
        list.AddObject(item);
        //save();
    }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.