开发者

How do I refactor three database operations that only differ by the method call?

I have three database operations like so:

public void Add<T>(T entity)
{
    using (var transaction = Session.BeginTransaction())
    {
        if (entity is IEnumerable)
        {
            foreach (var item in (IEnumerable) entity)
            {
                Session.Save(item);
            }
        }
        else
        {
            Session.Save(entity);
        }

        transaction.Commit();
    }
}

public void Update<T>(T entity)
{
    using (var transaction = Session.BeginTransaction())
    {
        if (entity is IEnumerable)
        {
            foreach (var item in (IEnumerable) entity)
            {
                Session.Update(item);
            }
        }
        else
        {
            Session.Update(entity);
        }

        transaction.Commit();
    }
}

public void Delete<T>(T entity)
{
    using (var transaction = Session.BeginTransaction())
    {
        if (entity is IEnumerable)
        {
 开发者_JS百科           foreach (var item in (IEnumerable)entity)
            {
                Session.Delete(item);
            }
        }
        else
        {
            Session.Delete(entity);
        }

        transaction.Commit();
    }
}

As you can see, the only thing that differs is the Session.[something] part. How would I refactor this into only one method?


Delegates look like a good solution here, as explained by other answerers. One other possible refactoring that could arguably simplify the inside logic would be a function that returns an IEnumerable. If the passed-in object is an IEnumerable, just return it; otherwise build a single-element enumeration with the passed-in object and return the enumeration. This would turn this:

if (entity is IEnumerable)
{
    foreach (var item in (IEnumerable) entity)
    {
       Session.Save(item);
    }
}
else
{
    Session.Save(entity);
}

into this:

foreach (var item in ForceEnumerable(entity))
    {
       Session.Save(item);
    }


You can make one method, and have it accept a delegate as a parameter, that specifies the action you want to do.

private void DatabaseAction<T>(T entity, Action<T> action) 
{
    using (var transaction = Session.BeginTransaction())
    {
        if (entity is IEnumerable)
        {
            foreach (var item in (IEnumerable) entity)
            {
                action(item);
            }
        }
        else
        {
            action(item);
        }

        transaction.Commit();
    }
}

Then refactor your 3 methods to:

public void Add<T>(T entity)
{
    DatabaseAction(entity, item => Session.Save(item));
}

public void Update<T>(T entity)
{
    DatabaseAction(entity, item => Session.Update(item));
}

public void Delete<T>(T entity)
{
    DatabaseAction(entity, item => Session.Delete(item));
}


You could pass in an Action<T> that should be performed for the entity:

public static void DoInTransaction<T>(this T entity, Action<T> action)
{
    using (var transaction = Session.BeginTransaction())
    {
        if (entity is IEnumerable<T>)
        {
            foreach (T item in (IEnumerable<T>) entity)
            {
                action(item);
            }
        }
        else
        {
            action(entity);
        }

        transaction.Commit();
    }
}

Example:

entity.DoInTransaction(Session.Save);
entity.DoInTransaction(Session.Update);
entity.DoInTransaction(Session.Delete);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜