2

In order to always make a first search in local DB context rather than DB itself and support the inclusion of related entities, I have the following extension method:

public static T LocalOrDatabase<T>(this DbSet<T> set, Expression<Func<T, bool>> criteria, params Expression<Func<T, object>>[] includes) where T : class {

    return LookUp(set.Local.AsQueryable(), criteria) ?? // Search local
           LookUp(set.AsQueryable(), criteria, includes); // Search database
}

private static T LookUp<T>(IQueryable<T> source, Expression<Func<T, bool>> criteria, params Expression<Func<T, object>>[] includes) where T : class {

    if (includes != null && includes.Any()) {
        foreach (Expression<Func<T, object>> include in includes) {

            source = source.Include(include);
        }
    }

    return source.FirstOrDefault(criteria);
}

Suppose these example entities:

[Table("entities1", Schema = "entities")]
public class Entity1
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Field1 { get; set; }

    public string Field2 { get; set; }

    public int? IdRelatedEntity1 { get; set; }

    [ForeignKey("IdRelatedEntity1")]
    public virtual RelatedEntity1 RelatedEntity1 { get; set; }

    public int? IdRelatedEntity2 { get; set; }

    [ForeignKey("IdRelatedEntity2")]
    public virtual RelatedEntity2 RelatedEntity2 { get; set; }

    public virtual List<RelatedEntity3> RelatedEntities3 { get; set; }
}

The way it is called:

Expression<Func<Entity1, bool>> criteria = e1 =>
    e1.Field1 == X &&
    e1.Field2 == Y;

_context.Entity1.LocalOrDatabase(criteria,
    // Includes
    e1 => e1.RelatedEntity1,
    e1 => e1.RelatedEntity2);

Nevertheless, by using this solution I'm not able to include, from Entity1, an inner field (RelatedEntity4) of the entity RelatedEntity3 because the relation between them isn't one-to-one.

Expected behaviour:

_context.Entity1.LocalOrDatabase(criteria,
    // Includes
    e1 => e1.RelatedEntity1,
    e1 => e1.RelatedEntity2,
    e1 => e1.RelatedEntities3.RelatedEntity4);

I need to kind of integrate the behaviour of "ThenInclude". Any ideas? I don't care drastic changes in the method.

SySc0d3r
  • 652
  • 1
  • 6
  • 18
  • You could take a look at [this](https://stackoverflow.com/a/47063432/861716), which allows you to use the old EF6 `Include` syntax. – Gert Arnold Aug 02 '18 at 08:36
  • There seems to be two issues here - one is the nested include syntax, and second is includes on local data. I think the second simply won't work because includes on non EF queryable are simply ignored. – Ivan Stoev Aug 02 '18 at 08:54
  • @Ivan Although the includes are only passed through when querying the set (which IMO makes the whole method disputable, but that's another topic). But I'm curious what you think of this `Include-ThenInclude`. Did you ever come up with something less cumbersome then my solution to re-enable includes as a `params` parameter? I wonder if the EF team realized they killed this frequently used parametrization when they invented the new `Include` syntax. – Gert Arnold Aug 02 '18 at 09:48
  • 1
    @Gert I was wondering the same. Looks like they think the new syntax is better, and expect people to use `Func, IIncludableQueryable>` instead of `params Expression>[]` - just a guess based on the code in their [Microsoft.EntityFrameworkCore.UnitOfWork](https://learn.microsoft.com/en-us/ef/core/extensions/#microsoftentityframeworkcoreunitofwork) – Ivan Stoev Aug 02 '18 at 12:00
  • 1
    @Ivan That's interesting! Seems so, yes. Works equally well I guess, just makes porting from EF6 to core a little bit harder. – Gert Arnold Aug 02 '18 at 12:09

0 Answers0