So I'm attempting to dynamically load my domain data service where the table name is the string ... Here's what I've got so far: Normally I'd load like this:
theDomainDataService.Load(theDomainDataService.getUsersQuery());
so I'm trying to automate which entity is loaded by the string name.
String theVariableEntityName = "Users";
Type t = theDomainDataService.GetType();
MethodInfo stuff = t.GetMethod("Get" + theVariableEntityName + "Query");
var theQuery = stuff.Invoke(theDomainDataService, null);
theDomainDataService.Load((EntityQuery<MySite.Web.Models.User>)theQuery);
---------------------------------------------------------^ Problem
This is in fact loading my domainDataService correctly, but what I need is a dynamic way to infer the type of the EntityQuery (without explicitly declaring it's going to be a User), because in fact it could be anything.
I have tried this from the DomainDataService Class with no luck, it isn't finding method's "Set" or "Entry".
public List<object> void PopulateEntity(string theEntityName)
{
Type theEntity = Type.GetType("MySiteMaintenance.Web.Models." + theEntityName);
using (var db = new DatingEntities())
{
IQueryable query = db.Set(theEntity);
foreach (var item in query)
{
var entry = db.Entry(item);
}
}
}
Remember, all I need is a populated entity (when all I have is the name of the entity) populated Client side... so I can say
DomainServiceClass theClass = new DomainServiceClass();
theClass.Load(theClass.GetEntityNameQuery());
so I can reference the appropriately loaded entity with...
theClass.Entity (users... questions, etc..)
I'm still not sure I follow, but...
I have a Post entity in my Sandbox namespace which I get from my DbContext instance using the entity type name in a string to start with...
// Get my entity type (if in same assembly, else you'll have to specify)
Type postType = Type.GetType("Sandbox.Post");
using (var db = new StackOverflowEntities()) {
// not required
db.Configuration.ProxyCreationEnabled = false;
IQueryable query = db.Set(postType);
foreach (var item in query) {
DbEntityEntry entry = db.Entry(item);
}
}
Which results in retrieving any DbSet based on a Entity type string. Below a breakpoint in the item foreach loop - revealing the values.
Related
I've this code and everything works just fine.
using (var db = new ApplicationDbContext())
{
md = db.Modles.ToList();
}
My question is that I have a parameter called M and that is the name of a Model I've created, so it can be dynamic.
Is there a way to do something like this:
var M = "Modles"; // or M = "Modles2"
using (var db = new ApplicationDbContext())
{
md = db[M].ToList();
}
I've tried Entity Framework Get Table By Name and Entity Framework get table by variable name but without any luck.
Can this be done?
The solution on second link you provided actually doesn't work because it's missing a simple step: The method Set on DbContext is a generic method, so you cannot simply invoke it without telling the type, either at compile time or at least at runtime. Since you want it to be called dynamically, runtime resolution is the option you're left with. The following example should work:
var entityNs = "myentities";
var table = "Model";
var entityType = Type.GetType($"{entityNs}.{table}");
var methodInfo = typeof(ApplicationDbContext).GetMethod("Set");
var generic = methodInfo.MakeGenericMethod(entityType);
dynamic dbSet = generic.Invoke(myContext, null);
var list = dbSet.GetList();
Reference: How do I use reflection to call a generic method?
I'm wondering, if it's even possible in the first place, how I would go about querying the database (using EF) using an ID and a table name.
For example, writing a function as:
QueryDynamicData(string tableName, long entityID){return GetItem(tableName, entityID);}
And could be called like:
var entry = QueryDynamicData("Person", 143);
To clarify, this is for a MVC ASP.Net project using Entity Frameworks.
Thanks in advance!
EDIT:
Following the example from #JPVenson, I came up with the following code. Note that it returns a list of Dictionaries, even though Id is unique, since I'm thinking ahead to when we may want to get all results for a dynamic table instead of just by Id. (This is only proof of concept level)
public List<Dictionary<string, object>> QueryDynamicData(string table, int entityID)
{
try
{
//Get the table desired based on the table name passed
PropertyInfo dbSetInfo = DBContext.GetType().GetProperties().FirstOrDefault(p => p.Name.ToLower().Equals(table.ToLower()));
//Return all results from the table into IQueryable set where Id = entityID passed
IQueryable anyDbSet = ((IQueryable)dbSetInfo.GetValue(DBContext)).Where("Id=" + entityID);
List<Dictionary<string,object>> listObjects = new List<Dictionary<String, Object>>();
//Iterate through results
foreach (Object entity in anyDbSet)
{
//Create dictionary of Field Name, Field Value from results
Dictionary<string, object> listDBValues = entity.GetType().GetProperties().ToDictionary(propertyInfo => propertyInfo.Name, propertyInfo => propertyInfo.GetValue(entity));
//Add dictionary to list of dictionaries - useful for returning list of found results instead of just one
listObjects.Add(listDBValues);
}
//Return list of dictionaries
return listObjects;
}
catch (Exception e) { }
return null;
}
Yes you can. There is a blog from ScottGu
https://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library
(MS Version of DynamicLinq https://github.com/kahanu/System.Linq.Dynamic/wiki)
that contains the wiki for a lib called DynamicLinq. I'm using it currently in a Project and it will fit your approach.
You still have to wrap it and use some Reflection to build a proper IQueryable but it does a lot of work for you
Edit Code Example
With some reflection you can access your dbSet like this (Untested Pseudocode!):
public object[] QueryDynamicData(string table, int entityId) {
//Your DbContext that contains all of your
var dbContext = new FooBaa()
//Get the DbSet in your DbContext that matches the "Table" name.
//You are searching for the generic parameter of the DbSet
var dbSetInfo = dbContext.GetType().GetProperties().FirstOrDefault(e => e.GetGenericArguments().Any(f => f.Name.Equals(table));
//Now get the DbSet from the DbContext and cast it to an IQueryabe
IQueryable anyDbSet = (IQueryable)dbSetInfo.GetValue(dbContext);
//Use Dynamic Linq to create a Query that selects an ID
//warning SQL-Injection possible checkout the 2nd argument of type IDictionary
return anyDbSet.Where("Id=" + entityId).ToArray();
}
I had a few minutes to work on this between meetings, and came up with this (add it to your DbContext class:
public dynamic FindEntity(string table, long Id)
{
PropertyInfo prop = this.GetType().GetProperty(table, BindingFlags.Instance | BindingFlags.Public);
dynamic dbSet = prop.GetValue(this, null);
return dbSet.Find(Id);
}
It uses some reflection to find the property on the DbContext with the name of the table, and grabs a reference to it. Then it calls Find on that DbSet<T> to find the object with the specified primary key. Since you aren't sending any actual Type information along, everything has to be dynamically typed.
You can call it like this:
using (var db = new MyContext())
{
var e = db.FindEntity("Animals", 1);
}
I can't vouch for how useful it will be do you, but it does return (dynamically typed) data in my test setup.
I'm looking for a method to getdatabase table's field with variable thing.
I wrote a stupid and unworking method to explain what I need:
using (var dbContext = new db_ReadyEngine_MSSQL())
{
string nameOfField = "UserName";
var table = dbContext.tbl_User;
foreach (var x in table)
{
string fieldValue = x.nameOfField;
}
}
Here, I'm trying to determining column name which it nameOfField...
You may call data from DataTable by using name of column, as example:
Object o = dataTable.Rows[0][nameOfField];
try this:
List<string>values = new List<string>();
using (var dbContext = new db_ReadyEngine_MSSQL())
{
values = (from s in dbContext.tbl_User select s.Username).ToList();
}
return values
Assuming I am reading your question correctly, you want to get the value of a column, whose name is only known at runtime?
If so, have a look at the code below. It will pull the properties from the object type, search for the one that matches the nameOfField value, and then pull attempt to pull a value from it.
foreach (var x in table)
{
var fieldValue = x.GetType().GetProperties().Where(a => a.Name == nameOfField).Select(p => p.GetValue(x, null)).FirstOrDefault();
}
U can use Reflection to get value of Property using its String Name
using (var dbContext = new db_ReadyEngine_MSSQL())
{
string nameOfField = "UserName";
var table = dbContext.tbl_User;
foreach (var x in table)
{
string fieldValue = typeof(x).GetProperty(nameOfField ).GetValue(x, null) as string;
}
}
You can use Entity SQL for this without typing the query itself:
IEnumerable<object> GetFieldValues<T>(DbContext context, string fieldName)
where T : class
{
var oc = ((IObjectContextAdapter)context).ObjectContext;
ObjectQuery<T> q = oc.CreateObjectSet<T>();
return q.Select("it." + fieldName)
.AsEnumerable()
.Select(x => x[0]);
}
The trick is that an ObjectSet (the predecessor, sort of, or DbSet) can easily be cast to an ObjectQuery, which is the base of Entity SQL. By default, the command text uses "it" as alias for the table in the query, so if you want the value of one specific field, you must prefix it by the alias, and there you go.
The Select returns a DbDataRecord. The first value from this record is returned.
The advantage of this method over others is that it only queries the requested field from the database.
Of course, if you know the type of the field in question up front, you can make a strong-typed version of this method.
I have annotated my Entity Framework Code First objects with some extra metadata, such as the DataTypeAttribute or possibly new, custom attributes. A version of this code (from http://www.minddriven.de/index.php/technology/dot-net/web/asp-net-mvc/check-data-annotations-from-code) works well to read the attributes once I have the EF Code First POCO object's Type object.
However, I cannot figure out how to go from the MetadataWorkspace, where I find all the entities:
ObjectContext objContext = ((IObjectContextAdapter)this).ObjectContext;
MetadataWorkspace mw = objContext.MetadataWorkspace;
var entities = mw.GetItems<EntityType>(DataSpace.OSpace);
to the POCO class Types I need to reflect on the Attributes.
How do I get from an EntityType to the POCO object or its proxy? Or alternatively, how can I find all the POCO objects in the context without GetItems()?
Relevant Links:
ASP.NET MVC Quick Tip: Check Data Annotations from code
How to read Custom Attributes using reflection set by Fluent API in EF 4.1
MSDN link about getting entities from proxies
There might be a direct way to do this but you can get the type from the full name
var types = from entity in entities
select Type.GetType(entity.FullName);
If I'm correct what you want - this should help as it describes a similar problem I posted a while ago:
How check by unit test that properties mark as computed in ORM model?
Also check this other post which kind of summarizes it all:
Get Model schema to programmatically create database using a provider that doesn't support CreateDatabase
(all are earlier posts of mine)
In short, I managed to read most of the information - but it's not
perfect (if I remember right, I cannot check right now) and has some
issues for certain situations, depends on what you need exactly).
If it helps anyone else, this my test harness code for dumping my DbContext POCO proxies from my EF setup (specifically an Effort CSV database):
MyContext ctx = new MyContext();
var metadata = ((IObjectContextAdapter)ctx).ObjectContext.MetadataWorkspace;
var schema = metadata.GetItems(DataSpace.SSpace).ToList();
Dictionary<string, List<string>> tables = new Dictionary<string, List<string>>();
Dictionary<string, System.Data.Entity.Core.Metadata.Edm.EntityType> types = new Dictionary<string, System.Data.Entity.Core.Metadata.Edm.EntityType>();
Dictionary<string, string> table_names = new Dictionary<string, string>();
foreach (var item in schema)
{
if (item.ToString().Contains("CodeFirstDatabaseSchema") && !item.ToString().Contains("_"))
{
string[] tableItem = item.ToString().Split('.');
string name = tableItem[1];
Debug.WriteLine("table_name: " + name);
if (!tables.ContainsKey(name))
{
System.Data.Entity.Core.Metadata.Edm.EntityType entity_type = item as System.Data.Entity.Core.Metadata.Edm.EntityType;
if (entity_type != null)
{
List<string> columns = new List<string>();
var members = entity_type.DeclaredMembers;
foreach (var member in members)
{
columns.Add(member.ToString());
}
Debug.WriteLine("columns:\n" + string.Join(",", columns));
tables.Add(name, columns);
types.Add(name, entity_type);
table_names.Add(name, item.MetadataProperties["TableName"].Value.ToString());
}
}
}
}
foreach (var table_name in tables.Keys)
{
List<string> columns = tables[table_name];
System.Data.Entity.Core.Metadata.Edm.EntityType entity = types[table_name];
string table_csv_name = table_names[table_name] + ".csv";
Debug.WriteLine("table_csv_name: " + table_csv_name);
var assembly_name = AssemblyName.GetAssemblyName("MyDLL.dll");
var proxy = metadata.GetItems<System.Data.Entity.Core.Metadata.Edm.EntityType>(DataSpace.OSpace).Where(v => v.Name == table_name).FirstOrDefault();
Type proxy_type = Type.GetType(proxy.FullName + ", " + assembly_name.FullName);
if (proxy_type != null)
{
var set = ctx.Set(proxy_type);
foreach (var row in set)
{
Debug.WriteLine("row: " + row);
}
}
}
I've then got code that dumps the DbSet objects back out to csv via reflection on the POCO properties. Note the CodeFirstDatabaseSchema literal above is from Effort I think, YMMV
I am still a beginner at writing C# and SQL and was wondering if someone could help me with this basic question. I have looked all over the internet and am still stuck.
I am trying to write a WCF service to access my database. I only need one method:
public PathDto GetPath(string src, string trg)
{
using (var context = new PathsEntities())
{
var p = (
from a
in context.src
where a.Target = trg
select a).Distance, Path;
}
}
where the parameter src is the table name, and the string trg is the entity's primary key.
Visual studio gives me the error: ...pathsService does not contain a definition for src because it is trying to look up the table "src" and not the string contained in the variable.
How can I use my parameter in the lookup statement?
I am going to assume you are using DbContext EF5.0 stuff
public PathDto GetPath(string tableType, string id)
{
using (var context = new PathsEntities())
{
var type = Type.GetType(tableType);
var p = context.Set(type).Find(id);
return (PathDto)p;
}
}
Seems you DON'T use EF 5.0 and have only got EF 4.0 and are using ObjectContext. Try this...no idea if it works since I don't really use EF 4.0. Alternatively download EF 5.0
public PathDto GetPath(string tableType, string id)
{
using (var context = new PathsEntities())
{
var type = Type.GetType(tableType);
var p = context.GetObjectByKey(new EntityKey(tableType, "id", id));
return (PathDto)p;
}
}