I currently have a complete generic repository but I'm missing one feature and that is to use 
Include() and Find() together.
So now I have:
public E FindById<E>(int id) where E : class
{
    return DataContext.Set<E>().Find(id);
}
called using
var person = PersonRepo.FindById<Person>(personId);
I would like to have something similar to:
var person = PersonRepo.FindByIdWithIncludes<Person>(personId,new[]{"State.Address"});
So, something along this lines (this is only a test):
public E FindByIdWithIncludes<E>(int id, string[] includes) where E : class
{
    var entitySet = DataContext.Set<E>();
    DbQuery<E> entityQuery;
    foreach (var include in includes)
    {
        entityQuery = entitySet.Include(include);
    }
    return entityQuery.Find(id); //this is were it breaks
}
Is it possible?
You cannot use Find directly - Find doesn't work with includes. You must use SingleOrDefault.
First you need to define interface for your entities to expose their key.
public interface IEntityWithId 
{
    public int Id { get; set; }
}
Next you can write simple method with constrain to get access to the key:
public E FindByIdWithIncludes<E>(int id, string[] includes) 
    where E : class, IEntityWithId
{          
    IQueryable<E> entityQuery = DataContext.Set<E>();
    foreach (var include in includes)
    {
            entityQuery = entityQuery.Include(include);
    }
    return entityQuery.SingleOrDefault(e => e.Id == id); 
}
Btw. you can use strongly typed includes - here is an example.
You could go also the other way around, to use Find, but in combination with Load. In some cases might be better performing than Include-SingleOrDefault, but it really depends on the scenario.
Non-generic example:
 private User GetByUID(int uID, bool includeDetails = false, bool includeAddresses = false)
 {
    var result = context.Users.Find(uID);
    if (includeDetails)
    {
       // load user-details (1:1 relation)
       context.Entry(result)
              .Reference<UserDetails>(us => us.UserDetails)
              .Load();
    }
    if (includeAddresses) 
    {
       // load user-addresses (1:m relation)
       context.Entry(result)
              .Collection(us => us.Addresses)
              .Load();    
    }
    return result;
 }
Should not be difficult to make it generic to your needs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With