1

Given the following code:

var time = ctx.Time.First();
var notes = time.Notes.ToList();

This will actually run 2 queries against the database.

Basically, I need to tap into the expression tree and do some custom checking to not return records where the deleted flag is set.

I can do this in the first call by deriving my own class from IDbSet and using

Expression IQueryable.Expression
{
    ... Add custom expression here
}

However, I don't know how to do override the expression tree in the 2nd call.

Any advice?

Scottie
  • 11,050
  • 19
  • 68
  • 109

1 Answers1

0

If you have a repository, let's say ISomeRepository defined as:

public interface ISomeRepository
{
    SomeDataModel Get(Func<SomeDataModel, bool> predicate);
}

and you implement a class that implements this interface:

public class SomeRepository : ISomeRepository
{
    public SomeDataModel Get(Func<SomeDataModel, bool> predicate)
    {
        return someDbSet.FirstOrDefault(predicate);
    }
}

When you call this method from somewhere else you would specify:

_someRepo.Get(p => p.SomeId == someId && !p.Deleted);

That way you don't have to bother with Expression.

Huske
  • 9,186
  • 2
  • 36
  • 53
  • This would not work for accessing `time.Notes` navigation-property. – haim770 Dec 03 '15 at 22:24
  • Can you process the notes when the information is returned? I know this is not the best approach because there could be a lot of notes. Another approach would be to say: time.Notes.Where(p => !p.Deleted).ToList(). – Huske Dec 03 '15 at 22:27
  • The real problem is that `IQueryable` navigation properties are not supported and that means EF is always fetching the entire related data (all `Notes` of that `time` entity). – haim770 Dec 03 '15 at 22:31
  • So which one contains Deleted? Time or Notes? – Huske Dec 03 '15 at 22:34
  • @HuseinRoncevic: They both do. We don't want to actually delete anything in our database, so we need to have a flag on each of our records. The lead dev wants this to be invisible to the average developer, thus overloading the DbSet and adding in our own IsDeleted == false. – Scottie Dec 03 '15 at 22:35
  • In that case First has an overload that accepts lambda, so use First(p => !p.Deleted) and use the same thing in Notes.Where(p => !p.Deleted). However, you might have a problem if Time does not return anything. It will throw an exception. FirstOrDefault could be a better option and then check if it is null before a call to Notes. – Huske Dec 03 '15 at 22:36