Home > Software engineering >  EF DB Context Is Null On Generically Retrieved Entities
EF DB Context Is Null On Generically Retrieved Entities

Time:01-05

I was tinkering around to figure out a way to unify a data access layer for some databases which have types that are identical field wise but reside in different EF DB contexts. I came up with something like this (plz ignore the string interpolation, this is just a prototype):

public static T FetchEvent<T>(System.Data.Entity.DbContext dbContext, int eventId) where T : class, IEvent
{
    var record = dbContext.Database.SqlQuery<T>($"SELECT * FROM Events WHERE EventId = {eventId}").SingleOrDefault();
    return record;
}

Each database has an Events table and the related EF entities implement IEvent, where IEvent is just the fields and their data types to mimic the table structure. With the generic T parameter, it's left up to the calling code to specify the proper local EF entity type when retrieving records.

The code runs and returns records however the EF context on the dynamic proxy object is null, so you can't make any updates to the entities.

My question: is there a way to get the EF context to persist when I am retrieving records in this fashion?

CodePudding user response:

Since all events have the same fields which can be extracted to then interface and assuming that concrete T's are mapped to corresponding contexts you can just use the DbContext.Set<T> method:

public interface IEvent
{
    public int EventId {get; set;}
    // rest of the props 
}

public static T FetchEvent<T>(System.Data.Entity.DbContext dbContext, int eventId) where T : class, IEvent
{
    var record = dbContext
        .Set<T>()
        .Where(e => e.EventId == eventId)
        .SingleOrDefault();
    return record;
}

CodePudding user response:

If we talk about method Database.SqlQuery then you can't use tracking feature. There is description from documentation:

Creates a raw SQL query that will return elements of the given type. The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type. Use the SqlQuery(String, Object[]) method to return entities that are tracked by the context.

As we can see in documentation you need to use DbSet.SqlQuery method. This method support tracking.

You can use this method something like it:

public static T FetchEvent<T>(System.Data.Entity.DbContext dbContext, int eventId) where T : class, IEvent
{
    var record = dbContext.Set(typeof(T)).SqlQuery($"SELECT * FROM Events WHERE EventId = {eventId}").SingleOrDefault();
    return record;
}
  •  Tags:  
  • Related