I redistribute the application to invert some dependencies. Part of the source code uses DbContext.Set<MyEntityType>() to receive the request for the request.
With the inverse, MyEntityType is no longer explicitly known in the code using DbContext.Set<MyEntityType>() , so now I use DbContext.Set(TypeVariable) .
Refactoring works to such an extent that the correct DbSet is returned.
However, the type of DbContext.Set(TypeVariable).Local is IList (containing an unknown type), where as the type of DbContext.Set<MyEntityType>().Local ObservableCollection<MyEntityType> is ObservableCollection<MyEntityType> . This means that it is now impossible to run Linq against DbSet.
The best workaround I have been able to achieve is to apply to an interface that implements MyEntityType and other entity types (no code specified for clarity)
var set = Context.Set(targetType); var entity = set.Local.OfType<IActionTarget>() .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate); var querables = set as IQueryable<IActionTarget>; entity = querables.FirstOrDefault(e => e.Id == key.Id && e.EffectiveDate == key.EffectiveDate);
So, two questions:
Why doesn't DbContext.Set(TypeVariable) return a strongly typed set?
Is there a better way to do dependency inversion?
Additional information on request
All about addictions. The model contains POCO classes that are stored through EF Code First in a typical way (but through the repository ) The ActionEvaluator accepts some incoming data and determines through the methods of the repository which actions should be performed - therefore, requests to DbSets.
There was only one type of input data (CSV of a certain format) in the source code, and the ActionEvaluator was heavily dependent on this data and knew which POCO classes are applicable to those CSV records.
Now we want to expand to use different CSV formats and web api messages. To do this, we need to invert the dependencies so that the DataSource tells the ActionEvaluator which POCO classes the records belong to. This is done using a type variable.
So ActionEvaluator can no longer use a generic type parameter, but it can pass a type variable to the repository, which uses it to find the correct DbSet.
The problem is the difference between the two DbSet lookup methods - DbContext.Set<AnEntity>() and DbContext.Set(TypeVariable) .
I assume that I am asking for an improvement in EF to make these two functionally equivalent in their return values, but this may not be possible since the types of the second version are determined at runtime.
Here is the full code of the method on request:
private IActionTarget DbContextGetEntity(Type targetType, IActionTarget key) { var set = Context.Set(targetType); if (set == null) { throw new Exception("Unable to find DbSet for type '{0}'".F(targetType.Name)); } // Look in the local cache first var entity = set.Local.OfType<IActionTarget>() .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate); if (entity == null) { // If not found locally, hit the database var querables = set as IQueryable<IActionTarget>; if (querables != null) { entity = querables.FirstOrDefault(e => e.Id == key.Id && e.EffectiveDate == key.EffectiveDate); } } return entity; }
Ideally, I want to replace
var entity = set.Local.OfType<IActionTarget>() .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);
with
var entity = set.Local.OfType(targetType) .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);