Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access a method in the context through unit of work?

If I have the following Context :

public partial class HRMainDataCTX : DbContext
{
    public HRMainDataCTX()
        : base("name=HRMainDataCTX")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

  //DbSets
    public virtual int SEARCHEMPLOYEE(Nullable<decimal> p_EMP_NUM, string p_EMP_NAME)
    {
        var p_EMP_NUMParameter = p_EMP_NUM.HasValue ?
            new ObjectParameter("P_EMP_NUM", p_EMP_NUM) :
            new ObjectParameter("P_EMP_NUM", typeof(decimal));

        var p_EMP_NAMEParameter = p_EMP_NAME != null ?
            new ObjectParameter("P_EMP_NAME", p_EMP_NAME) :
            new ObjectParameter("P_EMP_NAME", typeof(string));

        return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("SEARCHEMPLOYEE", p_EMP_NUMParameter, p_EMP_NAMEParameter);
    }
}

Now i implement Unit of work like this :

public class HRCTX : IDisposable
{
    private readonly HRMainDataCTX _context;

    public HRCTX()
    {
        _context = new HRMainDataCTX();
    }

    public HRCTX(HRMainDataCTX context)
    {
        _context = context;
    }
    public int Save()
    {
        return _context.SaveChanges();
    }

    public HRMainDataCTX Context
    {
        get { return _context; }
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

I don't know how to access the method (stored procedure) SEARCHEMPLOYEE through UOW in my code behind.

like image 989
Anyname Donotcare Avatar asked Mar 29 '16 10:03

Anyname Donotcare


People also ask

When to use Unit of Work pattern?

The Unit of Work pattern is used to group one or more operations (usually database CRUD operations) into a single transaction or “unit of work” so that all operations either pass or fail as one unit.

What is the purpose of Unit of Work?

The unit of work class serves one purpose: to make sure that when you use multiple repositories, they share a single database context. That way, when a unit of work is complete you can call the SaveChanges method on that instance of the context and be assured that all related changes will be coordinated.

What is Unit of Work in .NET core?

The Unit of Work is a type of business transaction, and it will aggregate all Repository transactions (CRUD) into a single transaction. Only one commit will be made for all modifications. If any transaction fails to assure data integrity, it will be rolled back.

Why to use Repository pattern in c#?

The Repository pattern makes it easier to test your application logic. The Repository pattern allows you to easily test your application with unit tests. Remember that unit tests only test your code, not infrastructure, so the repository abstractions make it easier to achieve that goal.


2 Answers

Well, in your case you would simply add another "Proxy-Method" for this method to your HRCTX proxy / UOW class, or - since HRCTX provides access to its underlying context - call it directly on the context like this:

HRCTX uow = new HRCTX(someContext);
uow.Context.SEARCHEMPLOYEE(123, "123");

But I also wanted to emphasize that the DbContext already represents a Unit of Work pattern (combined with a Repository pattern, see here). You are basically creating a proxy for your context, which - as far as I can see in this example - adds no further benefits or functionality, so I'd suggest to at least think about directly using your HRMainDataCTX and possibly getting rid of the HRCTX class.

like image 126
bassfader Avatar answered Oct 22 '22 11:10

bassfader


You may need to implement repositories along with your Unit Of work pattern if you want to encapsulate your DbContext and your business logic. (As suggested in the AspNet guidelines)

In a generic manner, your unit of work can handle repositories like this:

public class HRCTX : IDisposable
{
    private readonly HRMainDataCTX _context;
    private Dictionary<Type, object> Repositories { get; set; }


    public HRCTX()
    {
        _context = new HRMainDataCTX();
        this.Repositories = new Dictionary<Type, object>();
    }


    //Get and add a repository to the dictionary if ot does not exist
    public IRepository<TEntity> GetNonGenericRepository<TEntity, TRepository>() where TEntity : class
    {
        if (this.Repositories.Keys.Contains(typeof(TRepository)))
        {
            return this.Repositories[typeof(TRepository)] as IRepository<TEntity>;
        }
        var repoType = typeof(TRepository);
        var constructorInfo = repoType.GetConstructor(new Type[] { typeof(DbContext)});
        IRepository<TEntity> repository = (IRepository<TEntity>) constructorInfo.Invoke(new object[] { this._context});
        this.Repositories.Add(typeof(TRepository), repository);
        return repository;
    }

 public IRepository<TEntity> GetGenericRepository<TEntity>() where TEntity :     class
    {
        if (this.Repositories.Keys.Contains(typeof(TEntity)))
        {
            return this.Repositories[typeof(TEntity)] as IRepository<TEntity>;
        }

        IRepository<TEntity> repository = new Repository<TEntity>(this._context);
        this.Repositories.Add(typeof(TEntity), repository);
        return repository;
    }


}

The interface and base class of your repositories:

 public interface IRepository<TEntity> where TEntity : class
{
    TEntity Find(Expression<Func<TEntity, bool>> match);
}

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
    protected DbContext Context { get; set; }

    public Repository(DbContext context)
    {
       this.Context = context;
    }
    public TEntity Find(Expression<Func<TEntity, bool>> match)
    {
        return Context.Set<TEntity>().SingleOrDefault(match);
    }
}

Now is the part where you clearly encapsulate your business logic:

public class EmployeeRepository : Repository<Employee>
{

    public EmployeeRepository(DbContext context) : base(context) {

    }
    public override Employee Find(Expression<Func<TEntity, bool>> match)
    {
        // You can either use the base class method or implement your custom logic
    }

    //This is where you encapsulate your business logic
     public Employee FindSpecific(Nullable<decimal> employeeNum, string employeeName){
         return this.Context.SEARCHEMPLOYEE(employeeNum, employeeName);
     }
}

Then you can use your Unit Of Work to access you business logic in a domain driven design way.

HRCTX unitOfWork= new HRCTX(dbContext);
unitOfWork.GetNonGenericRepository<Employee, EmployeeRepository>().FindSpecific(1337,"1337");

It can seem to be too much for what you expected as an answer but I think you need to structure your application that way if you don't want to expose you DbContext / Dal directly.

Hope it helps !

like image 44
Yann RENAUDIN Avatar answered Oct 22 '22 11:10

Yann RENAUDIN