Emit DbContext.OnModelCreating every time a context is created

I first use entity structure code to work with my database. I have several tables with different names but the same structure and these tables are dynamically displayed in the database. How can I map the EntityFramework to one of these tables at runtime and use the data in the same way I work on DbContext objects?

What I did to get it working:

For example, my class that describes the structure of a dynamically created table SetElement

.

Here's my context:

public class DataContext : DbContext
{
    public DataContext()
        : base("RepositoryConnectionString") { }

    string setElementsTableId; // the name of table that need to be dynamicly mapped to 

    // Enforce model recreating
    public DataContext(string setElementsTableId)
        : this()
    {
        this.setElementsTableId = setElementsTableId;
    }


    /* some other entities */

    public DbSet<Entities.SetElement> SetElements { get; set; } // dynamicly mapped entity


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        /* come configurations */

        if (!string.IsNullOrEmpty(setElementsTableId))
        {
            modelBuilder.Entity<Entities.SetElement>().Map(x => x.ToTable(setElementsTableId)); // map SetElements property to dynamicly created table
        }
    }
}

      

How I use this:

public static void AddSetElements(ICollection<SetElement> setElements, string tableId)
    {
     using (ctx = new DataContext(tableId)) // configere DataContext to map tableId table for entity SetElements
       try
       {
           var num = ctx.SetElements.Count();
           ctx.SetElements.AddRange(setElements);
           ctx.SaveChanges();
       }
       catch (Exception e)
       {
       }
 }

      

I also have some methods for getting, deleting and deleting data from dynamically created tables that are the same with AddSetElements

.

Everything works the way I want, but only if it AddSetElements

works first, because the first time the datacontext DbContext.OnModelCreating

is created, it executes and sets up all mappings. But creating the next instance doesn't call DbContext.OnModelCreating

.

So my question is, how to call DbContext.OnModelCreating

every time an instance is created DataContext

, then I use DataContext(string setElementsTableId)

to create it?

I know my question is similar to "dynamic table mapping in EF", but I didn't find anything in the results.

By the way. If you know another way to solve my problem, please.

+3


source to share


2 answers


There is a built-in function that can solve your problem: `IDbModelCacheKey; the implementation of which should be registered in your config. The point is to create a different key for different contexts.

I would go for something like:

Configuration first

public class EntityFrameworkConfiguration: DbConfiguration
{
    public EntityFrameworkConfiguration()
    {
        this.SetModelCacheKey(ctx => new EntityModelCacheKey((ctx.GetType().FullName + ctx.Database.Connection.ConnectionString).GetHashCode()));
    }
}

      

Then the implementation of IDbModelCacheKey



public class EntityModelCacheKey : IDbModelCacheKey
{
    private readonly int _hashCode;

    public EntityModelCacheKey(int hashCode)
    {
        _hashCode = hashCode;
    }

    public override bool Equals(object other)
    {
        if (other == null) return false;
        return other.GetHashCode() == _hashCode;
    }

    public override int GetHashCode()
    {
        return _hashCode;
    }
}

      

Finally, your DataContext

public class DataContext : DbContext
{

  string setElementsTableId; 

  // use the setElementsTableId as extended property of the 
  // connection string to generate a custom key
  public DataContext(string setElementsTableId)
        : base(ConfigurationManager.ConnectionStrings["RepositoryConnectionString"] 
 + "; Extended Properties=\"setElementsTableId=" + setElementsTableId + "\"")
  {
    this.setElementsTableId = setElementsTableId;
  }

  public DbSet<Entities.SetElement> SetElements { get; set; } 

  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    if (!string.IsNullOrEmpty(setElementsTableId))
    {
        modelBuilder.Entity<Entities.SetElement>().Map(x => x.ToTable(setElementsTableId)); 
    }
  }
}

      

Hope this helps.

+4


source


No one seems to know the answer ...



Otherwise, one person told me that my question is pointless because storing data in multiple tables will not give any results. Better to add indexes to a database, partition table, or whatever. In other words, it is a problem with the database management system. But if anyone knows the answer, I would be very pleased to hear something about the EF hack.

0


source







All Articles