I have a dynamic method(dynamicQuery) that receives an Enum (which stored procedure) and a Dictionary<string,string>, which will populate SQLParameters based on the content of the dictionary.
Let's say I have 3 stored procedures in SQL server that takes different parameters
named sp_insert_product, sp_insert_person, sp_insert_house.
How will I force the dictionary to accept the specific strings to pass to the stored procedure based on what the stored procedure accepts?
Another view of comparison. An overloaded dictionary, as you would do with methods.
EDIT
POSSIBLE SOLUTION
I can probably create a check inside the method, dynamicQuery, to check that if the content of the dictionary, does align with the parameters of the specified stored procedure.
But I want to do the error checking before compile-time, as opposed to run-time checking which would decrease performance
I resorted to ADO.NET
Thank you
If I understand your question correctly, you can use an enum as key for the dictionary.
enum Procedures
{
insert_prod,
insert_person
};
var dic = new Dictionary<Procedures, string[]>();
If I understand what you're trying to do - then that's very hard to do if there is no rigid contract between the sites. But as long as the code that deals with both is close together, it usually isn't an issue, for example:
string DoSomething(string username, string value) {
var dict = new Dictionary<string,string> {
{ nameof(username), username },
{ nameof(value), value },
};
SomeHelper.ExecuteSP("sp_somesp", dict);
}
Note that the same thing can also be done via anonymous types and reflection, for example:
string DoSomething(string username, string value) {
SomeHelper.ExecuteSP("sp_somesp", new { username, value });
}
which is pretty-much the approach that "Dapper" takes (except Dapper has a lot of optimization built in to make the reflection not hurt).
Related
I'm working on a deserialization class in .NET, I have to develop a method that provides to me with a variable name that is stored in a string.
I have a string such as:
string string_name = "this_is_going_to_be_var_name";
Now what can I do so that my code dynamically declares a variable named this_is_going_to_be_var_name?
So to clear things up: There will be a deserialization class that will declare variables of the same names as strings provided as input with their PARENT TYPES as per wish of the Higher Level Programmer/User.
For Example: In javascript/jQuery, when I fetch JSON by making a request, the interpreter declares variable(s)/array(s) of the same name and assigns values to them. If {"var_name":"var_value"} is a JSON string, the interpreter will create a variable named var_name and will assign "var_value" to it such as json_data_object.var_name.
No you can't. C# variables are all statically declared.
The best thing you can do is create a dictionary and use keys instead of variable names.
// Replace object with your own type
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
myDictionary.Add("this_is_going_to_be_var_name", value_of_the_variable);
// ...
// This is equivalent to foo($this_is_going_to_be_var_name) in PHP
foo(myDictionary["this_is_going_to_be_var_name"]);
This isn't possible, variable names are defined at compile time, not run time.
One approach is to create a dictionary or hash table to map string names to objects to sort of achieve what you want.
Not sure what you meant by
my code dynamically declares a variable named
this_is_going_to_be_var_name?
but the .Net version of what explode does in PHP is Split:
string[] zz = "this_is_going_to_be_var_name".Split('_');
The only thing that I can think on the moment (I haven't tested it so I have no clue if it is possible), is to have a object of type dynamic and then try to set the fields at runtime using reflection and InvokeMember(), which I can give a chance that it will work since the there is no validation on objects of type dynamic.
UPDATE:
I have tested it with ExpendoObject and InvokeMember doesn't appear to work (at least not with the default binder, but I haven't tested it with DynamicObject and allthough I don't give it to much chances to work you might still try it, you can check out http://msdn.microsoft.com/en-us/library/ee461504.aspx on how to use DynamicObject.
Take a look on Dynamically adding properties to an ExpandoObject which essentially describes a method in which the dynamic object is being cast as a IDictionary and then you can add properties to it by using the standard dictionary access, while they are actually getting properties of the object.
I tested it in a sample project by having a dynamic object of type ExpendoObject and then I add another variable that referenced it using type IDictionary, and then I tried to set and get properties on both, as in the following example:
dynamic test = new ExpandoObject();
//reference the object as a dictionary
var asDictinary = test as IDictionary<string, Object>;
//Test by setting it as property and get as a dictionary
test.testObject = 123;
Console.Write("Testing it by getting the value as if it was a dictionary");
Console.WriteLine(asDictinary["testObject"]);
//Test by setting as dictionary and get as a property
//NOTE: the command line input should be "input", or it will fail with an error
Console.Write("Enter the varible name, ");
Console.Write("note that for the example to work it should the word 'input':");
string variableName = Console.ReadLine();
Console.Write("Enter the varible value, it should be an integer: ");
int variableValue = int.Parse(Console.ReadLine());
asDictinary.Add(variableName, variableValue);
Console.WriteLine(test.input);//Provided that the command line input was "input"
(Still however in your case since you will anyway not access the properties directly in code I don't see the need for it and you would probably be able to use a Dictionary directly, and I don't understand why you need them to be properties of the object, which is only needed if you want to reference them at compile time.
But maybe I am misunderstanding you and you are looking for a dynamic variable and not for a dynamic property [something that is available in PHP using the $$ syntax], if this is the case then note that in c# there are no variables at all as everything is encapsulated in a object).
You can also take a look in How can I dynamically add a field to a class in C# for more answers.
We are writing a custom activity. In this activity it is possible to set a database connection string and a name for a stored procedure. At runtime the stored procedure is executing. Now we have some stored procedures which has input parameters.
Is it possible to generate variables dynamically in WF 4.5 for each input parameter in the stored procedure? Reading the parameters from the stored procedure is not the problem, but I dont have any idea how to generate the variables.
Example:
The user enters a name for the stored procedure to be executed (2 input params #Variable1 and #Variable2). Now in the variables tab should be 2 variables: #Variable1 and #Variable2. If the user changes the name in the stored procedure then in the variables tab should be the new params (for example only #Variable2)...
We spent a lot of time on this issue. But the only thing we have learned is that the activity has to be a NativeActivity and the variables should be added in the CacheMetadata method. But if I add a variable with AddVariable() method nothing happens :(
If you are open to including third-party libraries, you could try using an ORM tool like Dapper to accomplish this. A Dapper query generally takes an anonymous type to supply its parameters. Typical code for creating a custom object from fields in a database would look something like this:
IDbConnection db = New IDbConnection(...);
int id = 527; // normally passed in - using a hard coded value would defeat the purpose...
string myQuery = "SELECT Engine, Transmission, Make, Model, BodyStyle FROM Table WHERE ID = #ID";
Car result = db.Query<Car>(myQuery, new { ID = id }).First();
So I believe that you could use reflection to pass in the type ("Car") using reflection and create an anonymous object or pass in an actual object with an "ID" property at runtime. It will automatically create a custom Car object with the resulting data, assuming that the Car object has properties of Engine, Transmission, Make, Model, BodyStyle, etc.
Note that if you don't supply the type you expect to get back, you get an ExpandoObject: Creating an anonymous type dynamically? - you may also be able to pass one of these in for your input parameters, which would mean that you could create it at runtime.
This guy came up with a generic method for Dapper that may help you: http://www.bradoncode.com/blog/2012/12/creating-data-repository-using-dapper.html
What he came up with is something like this:
IEnumerable<T> items = null;
// extract the dynamic sql query and parameters from predicate
QueryResult result = DynamicQuery.GetDynamicQuery(_tableName, predicate);
using (IDbConnection cn = Connection)
{
cn.Open();
items = cn.Query<T>(result.Sql, (object)result.Param);
}
return items;
I have a bunch of data in the form of a Lua table and I would like to parse that data into a usable structure in C#.
The problem with Lua tables is that there are optional fields, tables are very dynamic and are not just a dictionary with one type for the key and one type for the value. It's possible to have one Lua table with both string and integer keys, and values of type integer, string and even table.
Sadly, the data that I'm parsing makes use of the dynamic nature of the language and isn't really structured in any straight-forward way. This requires a dynamic representation of the data, using for example Dictionary<object, dynamic>.
The format of the data is e.g. (from http://ideone.com/9nzXvt)
local mainNode =
{
[0] =
{
Name = "First element",
Comments = "I have comments!",
Data = { {123, 456}; foo = { "bar" } }
},
[1337] =
{
Name = "Another element",
Data = { {0}; foo = nil }
}
}
Are there any libraries out there to do this? Is there any way to accomplish this without parsing the data character by character?
You can use the luainterface library
There's some sample code here.
You'll want to use a combination of DoFile (to load the file) and GetTable to read the table into a LuaTable object that you can use the result from c#. The LuaTable exposes an IDictionaryEnumerator through GetEnumerator.
EDIT:
if you had this table constructor:
local t = { os.time() }
print(t[1]);
the function in the constructor would need to be executed to initialize the data.
for constant literals, you can have string constants like so:
local a = [==[
hello
there""\"]==]
with different levels of equal signs
a numeric literal can have the form:
0X1.921FB54442D18P+1
with P as a binary exponent.
faithfully reproducing the lua syntax for constant literals without using the lightweight lua VM would require re-implementing a good chunk of the lua language spec. not much benefit it re-inventing the wheel.
I know this is an old post, but this could be useful for people who arrive here after this post...
You could also look at Xanathar's MoonSharp (Moon#) project; I have just started to try it and it seems to work well with wrapping up the dynamic tables, with nested tables etc. You just give the interpreter a a script and it will parse and hold the parsed objects in the interpreter context.
Links:
http://www.moonsharp.org
https://github.com/xanathar/moonsharp/
Example:
[TestMethod]
public void Test_GetProperty_ForValidTypeAndKey_ReturnsValue()
{
// Arrange
String luaScript = MockLuaScripts.TEST_OBJECT_WITH_STRING;
Script context = new Script();
String expectedResult = MockLuaScripts.ValidValue1;
// Act
/* Run the script */
context.DoString(luaScript);
/* Get the object */
DynValue resultObject = context.Globals.Get(MockLuaScripts.ObjectInstance1);
/* Get the property */
DynValue tableValue = instance.Table.Get((MockLuaScripts.ValidKey1);
String actualResult = tableValue.String();
/* Or you can use..
String actualResult = tableValue.ToObject<String>();
*/
// Assert
Assert.AreEqual(expectedResult, actualResult);
}
Apologies if the above code is not exactly correct as it is taken from one of my test classes and converted for posting here. Please excuse the wrapped up mock-data constants, but they are in essence the Lua script and expected values.
When trying to access entries in Lua table via an incorrect key the DynValue has a DataType of "Nil", so are easy to handle with a conditional check.
More examples on usage of Xanathar's Moonsharp can be found on Xanathar's website and his git hub repo. (See links below). He seems to be very helpful with any issues or questions that you may come across too.
Links:
http://www.moonsharp.org
https://github.com/xanathar/moonsharp/
I have started to write some extensions which have units test which show further usage in one of my repos (See links below)
Links:
https://github.com/dibley1973/MoonsharpExtensions
The problem I'm having is thus, we're building a data access layer using our existing ORM (it's an old one called Gentle) with the idea of moving to something like Fluent NHibernate. There are a few queries where we have to add custom clauses to the SqlBuilder in our existing setup, so for instance when retrieving some person objects we might be adding a clause like:
"PersonId in (SELECT PersonId from Orders where OrderValue > " + orderValue + " and OrderName = " + orderName
The point being that the parameters are being added directly in a string rather than as a parameterised query, it is possible in Gentle to add it as a parameterised query and this is what I've been working on. All our DALs inherit from a base GentleDAL, this is the class that actually constructs the Gentle query, adds the clauses and parameters etc. To add a parameterised clause in Gentle you have to do two things with your SqlBuilder object, you have to call sb.AddConstraint(string clause) to add your clause, and then for each parameter you have to call sb.AddParameter(string name, Type type), you can then construct your SqlStatement object from this, and only after that can you set the value for your parameter where you call stmt.SetParameter(string name, object value).
The way I have represented these parameters/clauses is I have created a class called GentleClauseCollection, this contains the clauses and parameters and has Add and Get methods for both of these things. Clauses are just strings and are stored internally in a List, the parameters are stored in a GentleParameter class which uses generics. The full code for GentleParameter is as follows.
public class GentleParameter<TParamType>
{
public string Name { get; private set; }
public TParamType Value { get; private set; }
public Type ParameterType {get { return typeof (TParamType); }}
public GentleParameter(string parameterName, TParamType parameterValue)
{
Name = parameterName;
Value = parameterValue;
}
}
There is no collection in .NET that I'm aware of that would let me store GentleParameter for different values of TParamType in the same collection, however it can be done using the DLR. In my GentleCollection class I store the parameters in a List and I get the parameters from this class as an IEnumerable. The Add method in my class is able to only allow GentleParameter's to be added so I know that my parameters will always have a Name, Value and ParameterType field which I can access.
My questions are: Given I could sacrifice the generics and change my parameter class Value property to be 'object' instead of T, have I overcomplicated things by using dynamic, what are the pros and cons of both approaches? Is there a third way to do this that I haven't thought of and how significant a performance impact am I likely to see by using dynamic given that all the method calls using the dynamic objects will be compiled at run time?
Thanks in advance for your help.
As sb.SetParameter is not generic and awaits an object, I would not make GentleParameter generic and hence I would not use the DLR.
Using dynamic doesn't seem over complicated to me. Method calls are resolved at runtime and it's cached the resulting invocation probably averages about 10x slower (we are talking nanoseconds). So it depends on how you are going to use it if it makes sense.
If you are always going to use it as type Object than yes you don't need to be using type dynamic not that it would have hurt anything.
If you want to be able to access properties than yes you should use dynamic, the result code will look cleaner than anything else you could do.
But even using dynamic you don't necessarily have to call the properties themselves dynamically, if you want to have as much static typing is possible you can have dynamic resolve a helper method that takes a generic form of your GentleParameter and do your work inside that.
...
private void HelperDoStuffWithGenericParam<T>(GentleParameter<T>param){
//Do stuff you have the static typing
}
So here's my dilemma. I'm trying to utilize Dynamic LINQ to parse a search filter for retrieving a set of records from an Azure table. Currently, I'm able to get all records by using a GenericEntity object defined as below:
public class GenericEntity
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
Dictionary<string, object> properties = new Dictionary<string, object>();
/* "Property" property and indexer property omitted here */
}
I'm able to get this completely populated by utilizing the ReadingEntity event of the TableServiceContext object (called OnReadingGenericEvent). The following code is what actually pulls all the records and hopefully filter (once I get it working).
public IEnumerable<T> GetTableRecords(string tableName, int numRecords, string filter)
{
ServiceContext.IgnoreMissingProperties = true;
ServiceContext.ReadingEntity -= LogType.GenericEntity.OnReadingGenericEntity;
ServiceContext.ReadingEntity += LogType.GenericEntity.OnReadingGenericEntity;
var result = ServiceContext.CreateQuery<GenericEntity>(tableName).Select(c => c);
if (!string.IsNullOrEmpty(filter))
{
result = result.Where(filter);
}
var query = result.Take(numRecords).AsTableServiceQuery<GenericEntity>();
IEnumerable<GenericEntity> res = query.Execute().ToList();
return res;
}
I have TableServiceEntity derived types for all the tables that I have defined, so I can get all properties/types using Reflection. The problem with using the GenericEntity class in the Dynamic LINQ Query for filtering is that the GenericEntity object does NOT have any of the properties that I'm trying to filter by, as they're really just dictionary entries (dynamic query errors out). I can parse out the filter for all the property names of that particular type and wrap
"Property[" + propName + "]"
around each property (found by using a type resolver function and reflection). However, that seems a little... overkill. I'm trying to find a more elegant solution, but since I actually have to provide a type in ServiceContext.CreateQuery<>, it makes it somewhat difficult.
So I guess my ultimate question is this: How can I use dynamic classes or generic types with this construct to be able to utilize dynamic queries for filtering? That way I can just take in the filter from a textbox (such as "item_ID > 1023000") and just have the TableServiceEntity types dynamically generated.
There ARE other ways around this that I can utilize, but I figured since I started using Dynamic LINQ, might as well try Dynamic Classes as well.
Edit: So I've got the dynamic class being generated by the initial select using some reflection, but I'm hitting a roadblock in mapping the types of GenericEntity.Properties into the various associated table record classes (TableServiceEntity derived classes) and their property types. The primary issue is still that I have to initially use a specific datatype to even create the query, so I'm using the GenericEntity type which only contains KV pairs. This is ultimately preventing me from filtering, as I'm not able to do comparison operators (>, <, =, etc.) with object types.
Here's the code I have now to do the mapping into the dynamic class:
var properties = newType./* omitted */.GetProperties(
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public);
string newSelect = "new(" + properties.Aggregate("", (seed, reflected) => seed += string.Format(", Properties[\"{0}\"] as {0}", reflected.Name)).Substring(2) + ")";
var result = ServiceContext.CreateQuery<GenericEntity>(tableName).Select(newSelect);
Maybe I should just modify the properties.Aggregate method to prefix the "Properties[...]" section with the reflected.PropertyType? So the new select string will be made like:
string newSelect = "new(" + properties.Aggregate("", (seed, reflected) => seed += string.Format(", ({1})Properties[\"{0}\"] as {0}", reflected.Name, reflected.PropertyType)).Substring(2) + ")";
Edit 2: So now I've hit quite the roadblock. I can generate the anonymous types for all tables to pull all values I need, but LINQ craps out on my no matter what I do for the filter. I've stated the reason above (no comparison operators on objects), but the issue I've been battling with now is trying to specify a type parameter to the Dynamic LINQ extension method to accept the schema of the new object type. Not much luck there, either... I'll keep you all posted.
I've created a simple System.Refection.Emit based solution to create the class you need at runtime.
http://blog.kloud.com.au/2012/09/30/a-better-dynamic-tableserviceentity/
I have run into exactly the same problem (with almost the same code :-)). I have a suspicion that the ADO.NET classes underneath somehow do not cooperate with dynamic types but haven't found exactly where yet.
So I've found a way to do this, but it's not very pretty...
Since I can't really do what I want within the framework itself, I utilized a concept used within the AzureTableQuery project. I pretty much just have a large C# code string that gets compiled on the fly with the exact object I need. If you look at the code of the AzureTableQuery project, you'll see that a separate library is compiled on the fly for whatever table we have, that goes through and builds all the properties and stuff we need as we query the table. Not the most elegant or lightweight solution, but it works, nevertheless.
Seriously wish there was a better way to do this, but unfortunately it's not as easy as I had hoped. Hopefully someone will be able to learn from this experience and possibly find a better solution, but I have what I need already so I'm done working on it (for now).