0

Im stuck on a generics issue. I have a method that returns DbSet from a DbContext object based on the object type.

Now I want to write I method where I pass in a object that implements a interface called IBaseData (that all entities implements). I want to use the existing method to return the correct DbSet based on the type of the IBaseData object, but I can't get it to work.

I've tried various versions of , typeof and gettype.

Existing method:

public GenericRepository<T> GetRepo<T>() where T : class
{
    return new GenericRepository<T>(_context);
}

New method (this is just what Im trying to do):

public async Task SetDateLastInvoked<T>(IBaseData data, int id)
{
    var tmp = GetRepo<typeof(data)>().Where(obj => obj.Id.Equals(id));
    tmp.DateLastInvoked = DateTime.Now;

    await SaveChangesAsync();
}
6
  • If you are using EF the problem you will run into is that EF does not support querying on interface properties, at least it didn't last I checked. This applies even if you are in a generic method Commented Dec 6, 2017 at 20:03
  • Ah okei. But what if all the entities derive from a class that implements the interface. So I don't pass in the interface but the object that implements it, if you understand what I mean ? Commented Dec 6, 2017 at 20:05
  • If you constraint the generic type on base type and not the interface I believe it will work, but I have not tested Commented Dec 6, 2017 at 20:07
  • If, the type of data is not known at compile time, to invoke the generic method you will need reflection as described here stackoverflow.com/questions/232535/… Commented Dec 6, 2017 at 20:12
  • What's the origin of the data object when it enters SetDateLastInvoked? More specifically, is it attached to a context ar that point? Commented Dec 6, 2017 at 20:16

2 Answers 2

1

I assume you are doing something like:

public interface IBaseData 
{
  int Id { get; set; }
}

Then a method would looe like

public GenericRepository<T> GetRepo<T>() 
  where T : class
{
  return new GenericRepository<T>(_context);
}

public async Task SetDateLastInvoked<T>(int id)
  where T : class, IBaseData
{
  var tmp = GetRepo<T>().FirstOrDefault(obj => obj.Id == id));
  tmp.DateLastInvoked = DateTime.Now;

  await SaveChangesAsync();
}

Usage:

public MyClass : IBaseData 
{ 
  public Id { get; set }
}

SetDateLastInvoked<MyClass>(1);
Sign up to request clarification or add additional context in comments.

2 Comments

@TheRuler won't hurt to also restrict your GetRepo<T> to where T: IBaseData - will prevent passing some type completely unrelated to your entities (which will fail at runtime).
I think I've done that now.. not exactly what you said, but where T : class, IBaseData
0

Ended up with this, based on previous answer:

public async Task SetLastInvoked<T>(int id) where T : class, IBaseData
{
    var tmp = await GetRepo<T>().Single(obj => obj.Id.Equals(id));
    tmp.DateLastInvoked = DateTime.Now;

    await SaveChangesAsync();
}

I also created another method based on the same pattern:

public async Task DeleteItem<T>(int id, bool removeRow) where T : class, IBaseData
{
    if (removeRow)
    {
        GetRepo<T>().Delete(await GetRepo<T>().Single(obj => obj.Id.Equals(id)));
    }
    else
    {
        var tmp = await GetRepo<T>().Single(obj => obj.Id.Equals(id));
        tmp.Active = false;
    }

    await SaveChangesAsync();
}

Comments

Your Answer

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.