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();
}
2 Answers 2
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_ID
s 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);
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();
}
_context.FLEX_INV_EXP_ADDRESS
? \$\endgroup\$