Generic Data Access Helper using Entity Fraamewark 6.1(Code First)


原文:http://www.codeproject.com/Articles/898206/Generic-Data-Access-Helper-using-Entity-Framework?msg=5044112#xx5044112xx
Motivation
When we write a simple logic that access database using EF&Linkq,it シンプルlooks like this:
ハイド   
Copyコード
public static List<Employee> GeAllEmployees()
{
    try
    {
        using (var northwindContext = new NorthwindDBContext())
        {
            var query = from e in northwindContext.Employees select e;
            return query.ToList();
        }
    }
    catch (Exception ex)
    {
        // Log Error
    }
}
So,I have to make this code redundent with a new business(e.g.  GetEmployeeOrders).Also,in case I have to access another database which means another  DBContext、I have to make this logic redundent!
ヘレ、ザ Generaics and Delegates come as a solution for those two ises.So I created a  public static class caled  DALHelper containing the following seven  static methods.
1 Querying
All retrieval's methods could also be used for saving changes to the database.
1.1 Default
The follwing snippet code is locking tables and this the default behavior of initiating a new  DbContext.
ハイド   
Copyコード
public static bool GenericRetrival<T>(Action<T> action) where T : DbContext, new()
{
    try
    {
        using (var context = new T())
        {
            action(context);
            return true;
        }
    }
    catch (Exception ex)
    {
	// Log Error
        return false;
    }
}
The usage
ハイド   
Copyコード
public List<Employee> GeAllEmployees()
{
	List<Employee> result= null;
	bool success = DALHelper.GenericRetrival<NorthwindDBContext>((northwindContext) =>
	{
		result = (from e in northwindContext.Employees select e).ToList();
	});
	return result;
}
1.2 Querying with a generic reult
ヘレwe identify  TResult  as geners of type  DBContext which a delegate of type  Func is going to return an object of  TResult  type.
ハイド   
Copyコード
public static TResult GenericResultRetrival<T, TResult>(Func<T, TResult> func) where T : DbContext, new()
    where TResult : new()
{
    try
    {
        using (var context = new T())
        {
            TResult res = func(context);
            return res;
        }
    }
    catch (Exception ex)
    {
        // Log Error
        return default(TResult);
    }
}
The usage
ハイド   
Copyコード
public List<Employee> GeAllEmployees()
{
	List<Employee> result = DALHelper.GenericResultRetrival<NorthwindDBContext,List<Employee>>((northwindContext) =>
	{
		return (from e in northwindContext.Employees select e).ToList();
	});
	return result;
}
1.3 Querying asynch ronously
ハイド   
Copyコード
public static async Task<TResult> GenericRetrivalAsync<T, 
	TResult>(Func<T, Task<TResult>> func)
    where T : DbContext, new()
    where TResult : new()
{
    try
    {
        using (var context = new T())
        {
            return await func(context);
        }
    }
    catch (Exception ex)
    {
	// Log Error
        return default(TResult);
    }
}
The usage
ハイド   
Copyコード
public async Task<List<Employee>> GetAllEmployeesAsync()
{
    return await DALHelper.GenericRetrivalAsync<NorthwindDBContext, List<Employee>>(async (northwindContext) =>
    {
        return await (from e in northwindContext.Employees select e).ToListAsync();
    });
}
1.4 A long query with ノロックニング tables asynchronously
ハイド   
Copyコード
public static async Task<TResult> 
GenericResultNoLockLongRetrivalAsync<T,TResult>(Func<T, Task<TResult>> func)
    where T : DbContext, new()
    where TResult : new()
{
    try
    {
        using (var context = new T())
        {
            ((IObjectContextAdapter)context).ObjectContext.CommandTimeout = 0;
            using (var dbContextTransaction = 
            	context.Database.BeginTransaction(IsolationLevel.ReadUncommitted))
            {
                return await func(context);
            }
        }
    }
    catch (Exception exception)
    {
        // Log Error
        return default(TResult);
    }
}
1.5 Querying from twice contexts asynchronously
ハイド   
Shrink 
   
Copyコード
public static async Task<object> 
	GenericTwiceContextsRetrivalAsync<T1, T2>(Func<T1, T2, Task<object>> func)
            where T1 : DbContext, new()
            where T2 : DbContext, new()
{
    try
    {
        using (var context1 = new T1())
        {
            using (
                var dbContextTransaction1 = context1.Database.BeginTransaction(IsolationLevel.ReadUncommitted))
            {
                using (var context2 = new T2())
                {
                    using (
                        var dbContextTransaction2 =
                            context2.Database.BeginTransaction(IsolationLevel.ReadUncommitted)
                        )
                    {
                        return await func(context1, context2);
                    }
                }
            }
        }
    }
    catch (Exception exception)
    {
        // Log Error

        return null;
    }
}
The usage
ハイド   
Copyコード
public async Task<object> GetDistributedDataAsync()
{
    return await DALHelper.GenericTwiceContextsRetrivalAsync<NorthwindDBContext, AdventureWorkDBContext>(async
        (northwindContext, advantureContext) =>
        {
            var employees = (from e in northwindContext.Employees select e).ToListAsync();
            var cutomers = (from c in advantureContext.Customers select c).ToListAsync();

            await Task.WhenAll(employees, cutomers);
            return new
            {
                EmployeeList = employees.Result,
                PersonList = cutomers.Result
            };
        });
}
So the design is going to be:Generic Data Access Helper using Entity Framework 6.1 (Code First)_第1张图片
2 Saving
2.1 Generic safe saving
I caled it safe as it could treat a set of trnsactions as an atom with comit/rollback logic. 
ハイド   
Copyコード
public static bool GenericSafeTransaction<T>(Action<T> action) where T : DbContext, new()
{
    using (var context = new T())
    {
        using (var dbContextTransaction = context.Database.BeginTransaction())
        {
            try
            {
                action(context);
                dbContextTransaction.Commit();
                return true;
            }
            catch (Exception ex)
            {
                dbContextTransaction.Rollback();
                // Log Error
                return false;
            }
        }
    }
}
The usage
ハイド   
Copyコード
public bool AddMultipleRecords(Employee newEmp, Supplier newSup)
{
    return DALHelper.GenericSafeTransaction<NorthwindDBContextgt;(northwindContext =>
    {
        northwindContext.Employees.Add(newEmp);
        northwindContext.SaveChanges();
        northwindContext.Suppliers.Add(newSup);
        northwindContext.SaveChanges();
    });
}
2.2 Saving asynch ronously
ハイド   
Copyコード
public static async Task<int?> GenericSafeTransactionAsync<T>(Action<T> action)
            where T : DbContext, new()
{
    using (var context = new T())
    {
        using (var dbContextTransaction = context.Database.BeginTransaction())
        {
            try
            {
                action(context);
                int affectedRecords = await context.SaveChangesAsync();
                dbContextTransaction.Commit();
                return affectedRecords;
            }
            catch (Exception ex)
            {
                dbContextTransaction.Rollback();
		// Log Error
                return null;
            }
        }
    }
}
The usage
ハイド   
Copyコード
return await DALHelper.GenericSafeTransactionAsync<NorthwindDBContext>( async (northwindContext) =>
{
	northwindContext.Employees.Add(newEmp);
});