Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query Context with Class Name only know at runtime

I am looking at creating a piece of code to allow me to dynamically query my database based on a string class name.

A brief overview of what I want here:

My Context:

public class MyContext : DbContext
{
    public DbSet<Foo> Foos {get;set;}
    public DbSet<Bar> Bars {get;set;}
}

With the set up I have, I query this context by doing the basic context.Foos.Where(...) and I essentially would like to do the same, but instead of having to know the .Foos part at compile time, would like it done at runtime.

Logically what I would like is:

var results = context."ClassName".Where(...)

I have tried to do this with a generic method like:

//method in context
public IEnumerable<T> GetGenericData<T>() where T : Type
{
    return context.Set<T>();
}

//call in repo
context.GetGenericData<Type.GetType("Foo")>();

Not sure if I am going down the right road here. Ideally I want to get a solution that means I won't have to go down the SQL route

EDIT: Been working on this further and I have gotten to this point.

//method in context
public DbSet GetGenericData(Type _type)
{
    return context.Set(_type);
}

//calling like
var data = context.GetGenericData(myType);

The issue now, is that the var data is a DbSet. I need to be able to convert this into a list of the Type that is defined at run time. Is there an easy solution to do this, as I can not just simply do var data = context.GetGenericData(myType).toList()

Edit2: To add some more context to the problem, I am looking at creating a piece of code to read a list of database tables from a file for example, get the data in these tables and serialize this into XML files.

Essentially I would have a file with the following:

Foo
Bar
MoreStuff

Which would then be read, and export all the data in the Foo table to an xml file called Foo.xml. Will also have to do the reverse, where in it reads the data from the xml files and imports it into the database

like image 513
Thewads Avatar asked Nov 14 '13 09:11

Thewads


1 Answers

If you don't know entity type at runtime but has type name, you could get type by name with help of reflection Type.GetType(string typeName) and use DbContext.Set overload like -> DbSet Set.Set(Type type)

more details at http://msdn.microsoft.com/en-us/library/gg679544(v=vs.113).aspx

UPDATE:

void Main()
{
    var typeMapping = new Dictionary<Type, Func<object, dynamic>>(){
        {typeof(A), a => (A)a}
    };
    var array = new[]{new A(){ o = new Object() },new A(){ o = new Object() },new A(){ o = new Object() },new A(){ o = new Object() },};    
    var objectArray = array.OfType<object>();
    objectArray.Select(a => typeMapping[a.GetType()](a)).Dump();

}

class A{
    public object o {get;set;}
}

This is sample from LinqPad. Your ask is about dynamic programing, i can't understand the purpose but still. In this paste you have to define type mappings for all your entity types like CLR type and convertion action which return refernce of needed type. The array variable is for example purpose and objectArray is as your data.

UPADATE2:

Mark your entity type with SerializableAttribute http://msdn.microsoft.com/en-us/library/system.serializableattribute(v=vs.110).aspx Than call ToList or ToArray extension like

var data = context.GetGenericData(myType).Tolist();

and serialize it with XmlSerializer like

var fileStream = File.OpenWrite("someFilePathName");
new XmlSerializer().Serialize(fileStream, data);

That's it! It would work because CLR would know exactly type of items in DbSet collection. And you don't have to cast to any. Then XmlSerializer would do all work necessary for serializer collection of entities and write it to stream wich is file stream. One more thing is to add some checks and add using block for IDisposable instances.

UPDATE3:

DbSet cannot be cast to exactly type with ToList bacause the idea is avoid using types in compile time for entity. So here is the idea of load data and cast it to object for continue manipulation

Set(typeof(TableBase)).Load();
var collectionToExport = Set(typeof (TableBase)).Local.Cast<object>().ToList();

and all together:

var type = Type.GetType("Foo");
context.Set(type).Load();
var collectionToExport = context.Set(type).Local.Cast<object>().ToList();
var fileStream = File.OpenWrite("someFilePathName");
new XmlSerializer().Serialize(fileStream, data);
like image 144
Vladimir Shmidt Avatar answered Nov 17 '22 01:11

Vladimir Shmidt