I need to get table data from table name from Linq DataContext.
Instead of this
var results = db.Authors;
I need to do something like this.
string tableName = "Authors";
var results = db[tableName];
It could be any table name that is available in DataContext.
Given DataContext context and string tableName, you can just say:
var table = (ITable)context.GetType()
.GetProperty(tableName)
.GetValue(context, null);
I am not sure if passing strings is an elegant solution. I would rather send the Type of entity as an argument to a method. Something on these lines :
var table = _dataCont.GetTable(typeof(Customer));
Here is the MSDN documentation.
I am not sure I'd suggest it as a GOOD solution, but if you really need it, you could do something like this:
MyDBContext db = new MyDBContext();
Type t = db.GetType();
PropertyInfo p = t.GetProperty("Authors");
var table = p.GetValue(db, null);
That will give you the Authors table, as pr. Table.
If you know the type, you can cast it. From http://social.msdn.microsoft.com/Forums/en-US/f5e5f3c8-ac3a-49c7-8dd2-e248c8736ffd/using-variable-table-name-in-linq-syntax?forum=linqprojectgeneral
MyDataContext db = new MyDataContext();
Assembly assembly = Assembly.GetExecutingAssembly();
Type t = assembly.GetType("Namespace." + strTableName);
if (t != null)
{
var foos = db.GetTable(t);
foreach (var f in foos)
{
PropertyInfo pi = f.GetType().GetProperty("Foo");
int value = (int)pi.GetValue(f, null);
Console.WriteLine(value);
}
}
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 need to dynamically get an entity object value from string.
something like this :
string s = "UserMaster";
string param = "MyUser";
object o = database.s.Find(param);
//I need o to become like object o = db.UserMaster.Find(MyUser);
Sorry I don't know the name if there's already a function to do this.
Thank you for your guidance :)
Edited :
Ok so here is the bigger picture :
string myString = "Hi my name is [UserMaster.Name] and my school is [SchoolMaster.SchoolName]";
Let's say I got string "[UserMaster.Name]" & "[SchoolMaster.SchoolName]",
UserMaster and SchoolMaster is an entity name.
UserMaster has 'Name' property and SchoolMaster has 'SchoolName' property.
I need to transform "[UserMaster.Name]" to its value, let's say "MyName"
and "SchoolMaster.SchoolName" to "MySchoolName".
You can use Expression to dynamically create code:
static object DynamicallyGet(string name, params object[] key) {
var entityName = Expression.Parameter(typeof(string), "entityName");
var keyValue = Expression.Parameter(typeof(object[]), "keyValue");
var db = Expression.Variable(typeof(RainDB), "database");
IList<Expression> procedures = new List<Expression>();
procedures.Add(Expression.Assign(db, Expression.New(typeof(RainDB))));
var entityType = typeof(RainDB).GetProperty(name);
var callMethod = Expression.Call(Expression.MakeMemberAccess(db, entityType), entityType.PropertyType.GetMethod("Find"), keyValue);
procedures.Add(callMethod);
var body = Expression.Block(new[] { db }, procedures);
var lambda = Expression.Lambda<Func<string, object[], object>>(body, entityName, keyValue).Compile();
return lambda(name , key);
//Call Function:
DynamicallyGet("UserMaster","MyUser")
Dynamically, when you have the DbSet as string (your case):
DbSet mySet = context.Set(Type.GetType("<Your Entity Name>"));
Source:
https://entityframeworkcore.com/knowledge-base/33940507/find-a-generic-dbset-in-a-dbcontext-dynamically
Besides all that, building dynamically a string that has parameters inside is common practice.
It is usually achieved by using curly brackets inside the string, e.g.:
this is in a database column:
"Hello, my name is {User.FirstName}, I come from {User.Country}"
These are usually predefined values and in code you can replace them because you expect them.
Then you do:
var userId = ...get this from session or from whatever you have in your context.
var dbUser = db.User.FirstOrDefault(x => x.UserId == userId);
var template = db.Templates.FirstOrDefault(x => x.TemplateName = "userTemplate");
// template is the Db table and TemplateValue is the column
var text = template.TemplateValue;
text = text.Replace("{User.FirstName}", dbUser.Firstname);
text = text.Replace("{User.Country}", dbUser.Country);
That works, but you have to know beforehand the parameters (they should be predefined).
If you have no idea what parameter should be sent (at least the sender should know that these exist as DB tables/columns), then yeah, it's more tricky and you should go with the dynamic approach that we suggested.
Good luck!
in my program, I use 4 stored procedures, depending on fields that were selected in the form.
ctx = new DataClassesDataContext();
items = (from prjs in ctx.sp_Select_Stuknummers(prjnr) select prjs).ToList();
or
ctx = new DataClassesDataContext();
items = (from prjs in ctx.sp_Select_Stuknummers_Scanner(prjnr, scanner) select prjs).ToList();
and so on ...
I use LINQ to SQL, and for each of these 4 queries, I have a different result class:
sp_Select_StuknummersResult
sp_Select_Stuknummers_ScannerResult
sp_Select_Stuknummers_Scanner_WPSResult
sp_Select_Stuknummers_StuknummerResult
they all have the same fields and definitions.
Now, when I iterate the result:
foreach (sp_Select_StuknummersResult x in items)
{
WPSitems ding = new WPSitems();
ding.ID = x.ID;
ding.Naam = x.Naam;
......
}
I need to pass the type to use (in this example: sp_Select_StuknummersResult )
Is there a way to either
A. easily convert to a new type, so that one can be used every time
or
B. dynamically set the type in the foreach loop ?
maybe there is even a C that I am not aware of...
Any help is highly appreciated !
By default, L2S auto-generates a separate type for each individual stored procedure. However, you can easily change that return type in the Linq-2-Sql Designer.
In the designer, click on the stored procedure. In the Properties window, there's an entry 'Return Type': change it from 'Auto-generated type' to the type you want.
If the stored procedure returns rows from an already mapped table, select that type in the drop-down. If not, you can manually add a class to the designer and configure that type to be returned from the stored procedure.
You can do this using generics/reflection.
public static WPSitems MapObjectWithIdenticalProperties<T>(T itemOfUnknownType) where T : new()
{
var inputType = typeof(T);
var outputType = typeof(WPSitems);
var outputItem = new WPSitems();
foreach (var inputProperty in inputType.GetProperties())
{
var matchingOutputProperty = outputType.GetProperties().FirstOrDefault(x => x.Name == inputProperty.Name);
if(matchingOutputProperty != null)
matchingOutputProperty.SetValue(outputItem, inputProperty.GetValue(itemOfUnknownType));
}
return outputItem;
}
The function above can be called like this:
var items = GetYourDataThatCanBeDifferentTypes();
var mappedItems = new List<WPSitems>();
foreach(var item in items)
mappedItems.add(MapObjectWithIdenticalProperties(item));
If I understand your problem correctly this might help you out:
1.) Create an interface for the result classes (e.g.) I_SP:
sp_Select_StuknummersResult
sp_Select_Stuknummers_ScannerResult
sp_Select_Stuknummers_Scanner_WPSResult
sp_Select_Stuknummers_StuknummerResult
add common variables and methods that you need into that interface.
2.) Make sure your items is List<I_SP>
3.) Create a generic method for your foreach loop
public void MyMethod<T>(List<I_SP> items) where T:I_SP {
foreach (var x in items.OfType<T>)
{
WPSitems ding = new WPSitems();
ding.ID = x.ID;
ding.Naam = x.Naam;
......
}
}
4.) Then just call this like this:
MyMethod<*sp_Select_StuknummersResult result class*>(items);
Hope it's clear enough.
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 need to figure out if it is possible to dynamically build a query with LINQ, dynamically selecting the table in which to perform the query.
This is an example of what I would do:
//Not working,just for example
public List<dynamic> _getGenericList(String tableName)
{
var l = from a in db.//I need to use here tableName
select a;
return l.ToList<dynamic>();
}
Is there a way to make this possible?
If the query is this simple you can dynamically create a standard sql statement and execute it, this is the most simplest way without using processor heavy reflection and complex code?
var query = "SELECT * FROM " + tableName;
var res = context.ExecuteQuery<dynamic>(query).ToList();
I've found a way to do it, but I'm not sure if I'd use this code. If you have a DataContext that contains two tables:
PrimaryTable
ID,
FirstValue,
SecondValue
SecondaryTable
ID,
FirstSecondaryValue
You could use the following DataHelper class:
class DataHelper
{
public MyDatabaseDataContext db = new MyDatabaseDataContext();
List<dynamic> GetDynamicList<T>() where T : class
{
System.Data.Linq.Table<T> table = db.GetTable<T>();
var result = from a in table select a;
return result.ToList<dynamic>();
}
public List<dynamic> GetWhatIWant(string tableName)
{
Type myClass = Type.GetType("DynamicLinqToSql." + tableName);
MethodInfo method = typeof(DataHelper).GetMethod("GetDynamicList", BindingFlags.NonPublic | BindingFlags.Instance);
method = method.MakeGenericMethod(myClass);
return (List<dynamic>)method.Invoke(this, null);
}
}
Then you can create an instance of your DataHelper and call the GetWhatIWant method, passing in the table name.
var dataHelper = new DataHelper();
List<dynamic> myFirstList = dataHelper.GetWhatIWant("PrimaryTable");
for (int i = 0; i < 5 && i < myFirstList.Count; i++)
{
System.Console.WriteLine(String.Format("{0} - {1}", myFirstList[i].FirstValue.ToString(), myFirstList[i].SecondValue.ToString()));
}
List<dynamic> mySecondList = dataHelper.GetWhatIWant("SecondaryTable");
for (int i = 0; i < 5 && i < mySecondList.Count; i++)
{
System.Console.WriteLine(mySecondList[i].FirstSecondaryValue.ToString());
}
System.Console.ReadKey();
I know this is old, but if you are here looking for answers like I was, then maybe this will help. I'm using a .NET ObjectContext directly instead of a DataContext data source. If you are using the DataContext version then you can simply (I hope) use queryResults = myGlobalContext.ExecuteQuery<dbGenericData>(query).ToList(); instead and I'm pretty sure it will work the same way.
Your tables will be a lot easier to work with if you have standards in naming and design like
the ID field for the table is always X type (INT, GUID, etc)
the ID field is always named tableNameID, the 'table name' with ID tagged on.
etc,
This will allow you to easily build the ID field by simply appending the 'ID' string onto the table name and will allow you to use a reliable CAST, if needed.
Speaking of CAST you will notice one in the query string. You will need to modify the use of the SQL string using CAST, changing field lengths like my nvarChar(50) example, etc, to overcome getting various TYPES of data from your database.
Final note: In the query string you will see I use the 'AS' key word to cast the DB field to a new name. I cast the 'tableIDField' into the name 'id' and I cast the 'requestedField' into the name 'dbData'. This allows the system to match up the renamed fields from the DB into the STRUCT object container we dump the data into. This allows you to construct generic containers to hold the data returned without having to worry about matching up with the DB field names.
I'm not a guru at this stuff, but I hope this helps somebody out.
private void testMethod(string requestedField, string tableName)
{
var tableIDField = tableName + "ID";
var query = "select " + tableIDField + " as id, CAST(" + requestedField + "as nvarchar(50)) as dbData from " + tableName;
List<dbGenericData> queryResults = null;
try
{
queryResults = myGlobalContext.ExecuteStoreQuery<dbGenericData>(query).ToList();
}
catch (Exception ex)
{
//Simply ignore any exceptions.
//These will need examined to determine best solution to unexpected results.
}
}
private struct dbGenericData
{
public dbGenericData(int id, string dbData)
{
this = new dbGenericData();
ID = id;
DBData = dbData;
}
public int ID { get; set; }
public string DBData { get; set; }
}
you can Generic Method and use db.Set<T> that return a DbSet Based on T
var esql = "select t from TypeName as t"
var q = db.CreateQuery(esql);
Use entity sql for linq to sql, http://esql.codeplex.com