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();
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jan 5, 2012 at 14:42
\$\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\$ Commented Jan 5, 2012 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\$ Commented Jan 5, 2012 at 16:46
  • \$\begingroup\$ what type is _context.FLEX_INV_EXP_ADDRESS? \$\endgroup\$ Commented Jan 5, 2012 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\$ Commented Jan 5, 2012 at 23:39
  • \$\begingroup\$ @k3b - Can't agree more, the idea was to make things simpler \$\endgroup\$ Commented Jan 6, 2012 at 8:55

2 Answers 2

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);
answered Jan 5, 2012 at 19:00
\$\endgroup\$
0
1
\$\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();
 }
answered Jan 5, 2012 at 18:06
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.