Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity framework: how to extend DbSet<type>?

I am trying to define my own DbSet, like:

public class MyDbSet<TEntity> : DbSet<TEntity>
    where TEntity : class
{
    public override TEntity Add(TEntity entity)
    {
      ....

And use it in DbContext

    public MyDbSet<User> Users { get; set; }

The problem I am facing is that Users will be null at runtime (and therefore useless) but I cannot figure why. Something like db.Users.Any( will throw a "value cannot be null"; if I replace and use DbSet instead like

    public DbSet<User> Users { get; set; }

everything works fine.

Does anybody know if and how can I fix this issue so I can use my own derived class?

Edit:

After receiving some comments, I clarify why I do this: I want to be able to switch easily from data retrieving mechanism to another without changing the code. For example if I decide to do caching in memory (caching is just an example, it may be I want to change some other things as well) I just override the Any/Find/... in MyDbSet and read from a dictionary instead of querying the database, leaving the rest of the code unchanged. This way the code will do "regular" operations without minding how the data is retrieved behind. So if somebody can point a method to do this without extending the DbSet class that will also answer the question.

many thanks

like image 484
user3346850 Avatar asked Nov 10 '22 11:11

user3346850


1 Answers

I've been down this road a couple times, and understand the desire to have it work this way, but in my experience it's not doable, or if it is, not worth the effort. The reason is that the many different storage engines (including in-memory cache) have differences that cannot be fit easily into EF. For example, a trivial in-memory cached implementation of a DbSet may not honor transactions, lazy- or eager- loading schemes, etc. My thought was that I'd like to be able to swap in Azure Table Storage. But with that sorting, paging, and querying is not as rich as SQL Server. Some queries you can do with SQL you just can't do with Azure Tables. In the end, I always come back to believing that the ability to swap out persistence engines behind EF sounds appealing, but is way more complex than just implementing a few classes- and in my apps not usually worth it.

If I wanted to support caching and was doing an ASP.NET Web API, I would consider using ASP.NET caching so that API requests/responses were cached at that point.

If I wanted support for different relational DB vendors, I would use the 3rd party EF Providers: A list of Entity Framework providers for various databases Incidentally, they do link to Caching and Tracing EF Providers- no idea if that works for newer EF.

If I wanted caching inside the data layer, or multiple storage engines that were drastically different (ie Mongo, Azure, and SQL), I would do it "above" the EF layer. Something like this:

 public interface ISomeDataProvider
 {
     SomeType Find(int id); 
     ....
 }

 public class EfDataProvider : ISomeDataProvider
 {
     private SomeAppDbContext db = new SomeAppDbContext();
     public SomeType Find(int id){
         return db.SomeTypes.Find(id);
     }

 }

 public class AzureTableDataProvider : ISomeDataProvider
 {
     public SomeType Find(int id){
         return //Azure Table code
     }

 }

 public class CachingDataProvider : ISomeDataProvider
 {
     private ISomeDataProvider source;
     private static IList<SomeType> cache = new List<SomeType>(); //List used here, but could use .NET Cache, Redis, etc.
     public CachingDataProvider(ISomeDataProvider source){
            this.source = source;
     }
     public SomeType Find(int id){
         var result = cache.SingleOrDefault(x=>x.Id == id)
         if(result == null){
             result = source.SingleOrDefault(x=>x.Id == id)
             if(result != null) cache.Add(result); //Again, trivial cache example.  Cache expiration, refresh, loading, etc. should be considered per-app
         }
         return result
     }

 }

That said, for the majority of my applications, when I think about it, the ability to swap out persistence engines isn't really a requirement. My customers don't "some want SQL, some want Azure Tables". That may just be due to the type of work we do, but in the end, it ends up being a dependency I just accept and code directly to EF.

like image 71
Daniel Avatar answered Nov 15 '22 08:11

Daniel