You can create and use tables in DB dynamically, although it's not so simply.
First, you'll need to store metadata about your tables — what are their names, what are properties they have, what are the types of those properties, and so on.
Second, you'll need to generate entities to access these tables, and also, EntityTypeConfiguration
classes, like here:
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FooTypeConfiguration : EntityTypeConfiguration<Foo>
{
public FooTypeConfiguration()
{
ToTable("Foos");
HasKey(t => t.Id);
Property(t => t.Name).HasMaxLength(200)
.IsRequired();
}
}
You can generate DLL dynamically without intermediate C# code with help of System.Reflection.Emit
. Or you can generate C# code and use System.CodeDom.Compiler
to compile it (this way is simpler). You can also try Roslyn compiler (but I don't have enough experience to advise it).
Third, you'll need to load compiled DLL and create DbContext
using modelBuilder.Configurations.AddFromAssembly(...)
.
You can find required type in assembly and use it to access data:
string typeName = ...;
var type = dynamicLoadedAssembly.GetType(typeName);
var set = dbContext.Set(type); // non-generic DB Set
You can use System.Reflection
or dynamic
typing to work with these objects.
Finally, if you'll generate C# code, you can generate properties and implementation of some interface to access these properties by names:
public interface IAccessorByName : IReadOnlyDictionary<string, object>
{
object this[string name] { get; set; }
}
public Foo : IAccessorByName
{
private static readonly IDictionary<string, Func<Foo, object>> getters = new Dictionary<string, Func<Foo, object>>
{
{ "Id", (foo) => foo.Id },
{ "Name", (foo) => foo.Name },
};
private static readonly IDictionary<string, Action<Foo, object>> setters = new Dictionary<string, Action<Foo, object>>
{
{ "Id", (foo, value) => { foo.Id = (int)value; } },
{ "Name", (foo, value) => { foo.Name = (string)value; } },
};
public int Id { get; set; }
public string Name { get; set; }
public object this[string name]
{
get { return getters[name](this); }
set { setters[name](this, value); }
}
}
With similar interface you can create, read, update, and delete objects dynamically:
string typeName = "Foo";
var fooType = dynamicLoadedAssembly.GetType(typeName);
var foo = (IAccessorByName)Activator.CreateInstance(fooType);
foo["Id"] = 1;
foo["Name"] = "Jon Skeet";
var fooSet = dbContext.Set(fooType);
fooSet.Add(foo);
dbContext.SaveChanges();