1

I implemented generic repository pattern and unitofwork. I used basic patterns and they work great. In project I have requirement which says, every table has several fields which contains long, really long text, and user should have ability chose and open any of it. As each field named differently i decided to use power ov generics with reflection, to write method which resieves table name and field name and returns it. Method, in generic Repository class, i wrote looks like this, it seems work properly

    public interface IRepository<T> where T : class
    {
        //other methods

        string GetPropertyByName(int id, string property);
    }

    public class Repository<T> : IRepository<T> where T : class
    {
        // other methods. add, edit, delete...

        public string GetPropertyByName(int id, string property)
        {
           T model =  this.Get(id);          
           var obj = model.GetType().GetProperty(property).GetValue(model, null);
           return obj != null ?  obj.ToString() : null;
        }
    }

I creted model classes for tables with help EF. Some tables binds directly genric repository, while other have separate interface and its implementation, as they require additional method. Example:

public interface ICompanyRepo : IRepository<COMPANY>
{
    //some methods
}

public class CompanyRepo : Repository<COMPANY>, ICompanyRepo
{
    //implementations of interface methods
}

And UOW implementation:

public interface IUnitOfWork
{
    ICompanyRepo Company { get; }        
    IRepository<CURRENCY> Currency { get; }        
}

public class UnitOfWork : IUnitOfWork
{
    static DBEntities _context;
    private UZMEDEXPORTEntities context
    {
        get
        {
            if (_context == null)
                _context = new DBEntities();
            return _context;
        }
    }
    public UnitOfWork()
    {
        _context = context;
        Company = new SP_CompanyRepo();
        Currency = new Repository<CURRENCY>();

    }

    public ICompanyRepo Company { get; private set; }
    public IRepository<CURRENCY> Currency { get; private set; } 
}

I have problem on invoking GetPropertyByName() method in business layer. I tried this:

public string GetHistory(string tableName, string fieldName, int id)
    {
        var prop = unitOfWork.GetType().GetProperty(tableName);
        MethodInfo method;
        method = prop.PropertyType.GetMethod("GetPropertyByName"); //try to find method
        if(method == null) //if method not found search for interface which contains that method
           method = prop.PropertyType.GetInterface("IRepository`1").GetMethod("GetPropertyByName");
        var res = method.Invoke(prop, new object[] { id, fieldName });
        return (string)res;
    }

Which returns System.Reflection.TargetException. As I understood the problem is whith unitofwork implementation. In my invoke method "prop" is type of interface (ICompanyRepo), but invoke's target should be interface implementation class, in this case "CompanyRepo". I could not find how to identify type of implementetion class, and solve this problem. Any help is appropriated

Mansur Anorboev
  • 580
  • 1
  • 7
  • 17
  • 1
    Side note: "Generic method" has very specific meaning in C# - code shown in the post does not show any generic methods - please [edit] post to either show real generic method (like `Foo()`) or use some other word instead... – Alexei Levenkov Dec 27 '16 at 06:07
  • The method is inside generic class, Repository so i thought it is correct to call method generic too. Anywat you are right, edited that part of question @AlexeiLevenkov – Mansur Anorboev Dec 27 '16 at 06:21
  • 1
    I see. Please read [MCVE] guidance on posting code. There is no way to know if `TEntity` is specific type (with strange naming convention) or parameter of generic type based on code provided in the post. – Alexei Levenkov Dec 27 '16 at 06:23
  • Thank for your notes. Tried clarify question. Should i give stucture of other inface/classes, like ICompanyRepo and CompanyRepo. Or there is already enough information – Mansur Anorboev Dec 27 '16 at 06:44
  • Updated question, and tried to be more specific and give more information. Hope question is clear now. Also added some code changes I did in last hour @AlexeiLevenkov – Mansur Anorboev Dec 27 '16 at 07:17
  • 1
    Code looks plausible - not sure what exactly is wrong. You may want to create real [MCVE] that does not involve extra classes to see if you can simplify sample. Also `TargetException` likely has more info - see if it helps debugging... Note that `prop` can't hold reference to an interface as interfaces don't have instances even if variable type is an interface. – Alexei Levenkov Dec 29 '16 at 21:33
  • 1
    Have you considered `dynamic prop` instead of all manual reflection code? – Alexei Levenkov Dec 29 '16 at 21:33

1 Answers1

0

I am not sure that this is best option, but problem solved with use of ToExpando() extension given here. With this extension i could loop throw all properties of unitofwork and find required property by its name.

var propValue = unitOfWork.ToExpando().Single(x => x.Key == prop.Name).Value;
var res = method.Invoke(propValue, new object[] { id, fieldName });

Now method is invoking properly. May be there is cleaner solution, and I still hope to find this. For now i am going to use this solution, and just realised that I must read and practice a lot about reflections, dynamics and generics. P.S Special thanks to Alexei for important notes and advices

Community
  • 1
  • 1
Mansur Anorboev
  • 580
  • 1
  • 7
  • 17