Call Method by string value from data base - c#

So I have a cell in my Oracle table, its value will be some System function or some Static Property like DateTime.Now.Year.
at the table cell the type is VARCHAR2 in .Net its string.
How can I produce a Generic Code for each case (Property, static Function) to get the value in the string
string str = "DateTime.Now.Year" // the value comes from DataBase
var valueFromDataBase = str.invoke();

Considering you're storing a type and a property
public class Entity
{
public string TypeName { get; set; }
public string PropertyName { get; set; }
}
new Entity { TypeName = typeof(DateTime).FullName ; PropertyName = nameof(DateTime.Now) }
using reflection you can now reverse the process
public static object? GetPropertyValue(string typeName, string propertyName)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var types = assemblies.SelectMany(a => a.GetTypes());
var type = types.First(t => t.FullName == typeName);
var property = type
.GetProperties(BindingFlags.Public | BindingFlags.Static)
.First(p => p.Name == propertyName);
return property.GetValue(null);
}
var datetime = GetPropertyValue(entityFromDb.TypeName, entityFromDb.PropertyName);

Related

How to get type from attribute to execute method?

I want to know you can I get by reflection a Type to execute a method that implements a certain interface.
System.Attribute implementation
[AttributeUsage( AttributeTargets.Property )]
public class ExampleAttribute : Attribute
{
public ExampleAttribute( string key )
{
Key = key;
}
public string Key { get; set; }
public Type Executor { get; set; }
}
Model that uses the attribute annotation (AttributeTargets.Property)
public class Example
{
[ExampleAttribute( "property" )]
public string Property { get; set; }
[ExampleAttribute( "lock", Executor = typeof( LockExecutor ) )]
public string Lock { get; set; }
}
public interface IExecutor
{
object TranslateValue( object value );
}
public class LockExecutor: IExecutor
{
public object TranslateValue( object value )
{
var lock = value.ToString() == "LOCK";
return lock;
}
}
I want to know how can I get by reflection the object of type IExecutor to execute the specific implementation (LockExecutor).
I hope it is not trying to translate something and it is just an abstraction.
var ex = new Example{Property = "Prop", Lock = "LOCK"};
var type = ex.GetType();
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public) // get properties
.Select(t =>
{
var attr = t.GetCustomAttribute<ExampleAttribute>(); // read attribute
var executor = attr == null ? null :attr.Executor; // it has attribute?
IExecutor instance = null;
if (executor != null) // attribute has executor
instance = (IExecutor)Activator.CreateInstance(executor); // create instance
return new
{
Property = t, Executor = instance
};
}
).Where(t => t.Executor != null).ToList(); // select the ones which has executor
properties.ForEach(t =>
{
var val = t.Property.GetValue(ex); // get value from instance
var translated = t.Executor.TranslateValue(val); // execute
Console.WriteLine(translated); // dump
}
);
Fiddle
I am not sure what is the rational behind the requirement, but you can use this code:
var example = new Example() { Property = "x", Lock = "y" };
var property = example.GetType().GetProperty("Lock");
var attribute = property.GetCustomAttributes(true).OfType<ExampleAttribute>().FirstOrDefault();
var executer = Activator.CreateInstance(attribute.Executor);
var method = attribute.Executor.GetMethod("TranslateValue");
var result = method.Invoke(executer, new[] { example.Lock });

Dynamically sort collection navigation property using linq

I am attempting to sort a collection based on a property.
So I do not know the property until runtime that I want to sort on.
The following works on the primary object but not any child objects
var prop = TypeDescriptor.GetProperties(typeof(TvRequests)).Find(sortProperty, tru
if (sortProperty.Contains('.'))
{
// This is a navigation property currently not supported
prop = TypeDescriptor.GetProperties(typeof(TvRequests)).Find("Title", true);
}
allRequests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
? allRequests.OrderBy(x => prop.GetValue(x)).ToList()
: allRequests.OrderByDescending(x => prop.GetValue(x)).ToList();
So the sortProperty is passed into my method and is a string and can be something like title or date and it works. But if I attempt to access a child property of my TvRequests object it will not work e.g. requestedUser.username
This is a trimmed down version of my objects that I'm referring to in this question:
public class TvRequests
{
public string Title { get; set; }
[ForeignKey(nameof(RequestedUserId))]
public OmbiUser RequestedUser { get; set; }
}
public class OmbiUser
{
public string Username;
}
My question is how would I be able to access any children properties like the above dynamically?
Use EF.Property.
// Get the string name of the property here
string propertyName = "Title";
allRequests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
? allRequests.OrderBy(x => EF.Property<string>(x, propertyName)).ToList()
: allRequests.OrderByDescending(x => EF.Property<string>(x, propertyName)).ToList();
Something along the lines may work (untested, but compiles)
// static for caching & performance
static private MethodInfo efPropertyGenericMethod = typeof(EF).GetTypeInfo().GetDeclaredMethod("Property");
Expression SortBy<TEntity>(Type type, string propertyName)
{
var xParam = Expression.Parameter(typeof(TEntity), "x");
// set T generic type here for EF.Property<T>
var efPropertyMethod = efPropertyGenericMethod.MakeGenericMethod(type);
// Creates a Lambda
Expression lambda = Expression.Lambda(
// Calls a method. First parameter is null for static calls
Expression.Call(null,
efPropertyMethod, // our cosntructed generic Version of EF.Property<T>
xParam, // Pass the x Parameter
Expression.Constant(propertyName, typeof(string)) // the propertyName asconstant
),
xParam
);
return lambda;
};
To be used as
allRequests.OrderBy(SortBy<TvRequests>(propertyType, propertyName))
Please note that that SortBy isn't called within the lambda. The below would be wrong (there's no x => in the line above).
allRequests.OrderBy(x => SortBy<TvRequests>(propertyType, propertyName))
What it does? SortBy generates an expression tree equivalent of x => EF.Property<T>(x, "MyPropertyName").
Edit:
Updated the method, so x is also passed to EF.Property(x, propertyName)
you can try something like this..
public static class QueryableExtensions
{
public enum SortDirection { ASC,DESC}
static LambdaExpression CreateExpression(Type type, string propertyName)
{
var param = Expression.Parameter(type, "x");
Expression body = param;
body = propertyName.Split('.')
.Select(prop => body = Expression.PropertyOrField(body, prop))
.Last();
return Expression.Lambda(body, param);
}
public static IQueryable<T> SortBy<T>(this IQueryable<T> source,string expressionField,SortDirection sortDirection = SortDirection.ASC)
{
var lambdaExpression = CreateExpression(typeof(T), expressionField) as dynamic;
return sortDirection == SortDirection.ASC ? Queryable.OrderBy(source,lambdaExpression) : Queryable.OrderByDescending(source, lambdaExpression);
}
}
types
public class TvRequests
{
public string Title { get; set; }
public OmbiUser RequestedUser { get; set; }
public DateTime Date { get; set; }
}
public class OmbiUser
{
public string Username;
public DateTime Date { get; set; }
}
using
List<TvRequests> reqList = new List<TvRequests>();
reqList.Add(new TvRequests {
Title = "A",
Date = DateTime.Now.AddDays(-1),
RequestedUser = new OmbiUser
{
Username = "A",
Date = DateTime.Now.AddDays(-1)
}
});
reqList.Add(new TvRequests
{
Title = "C",
Date = DateTime.Now.AddDays(1),
RequestedUser = new OmbiUser
{
Username = "C",
Date = DateTime.Now.AddDays(1)
}
});
reqList.Add(new TvRequests
{
Title = "B",
Date = DateTime.Now,
RequestedUser = new OmbiUser
{
Username = "B",
Date = DateTime.Now
}
});
foreach (var item in reqList.AsQueryable().SortBy("Date", SortDirection.DESC))
Debug.WriteLine(item.Title);
foreach (var item in reqList.AsQueryable().SortBy("RequestedUser.Date"))
Debug.WriteLine(item.Title);
foreach (var item in reqList.AsQueryable().SortBy("RequestedUser.UserName",SortDirection.DESC))
Debug.WriteLine(item.Title);

How to create a dynamic LINQ select projection function from a string[] of names?

Using C#...
Is there any way to specify property names for a projection function on a LINQ select method, from an array.
public class Album
{
public int Id { get; set; }
public string Name { get; set; }
public short Rate { get; set; }
public string Genre { get; set; }
public short Tracks { get; set; }
}
public class Class1
{
private void Some<T>()
{
// Example of source
var names = new[] { "Id", "Name", "Tracks" };
var query = myDataContext.
GetTable<T>.
AsQueryable().
Select( /* dynamic projection from names array */ );
// something like
// Select(x => new
// {
// x.Id,
// x.Name,
// x.Tracks
// }
GoAndDoSomethingWith(query);
}
}
Could this be done without System.Linq.Dynamic?
You could use reflection and dynamic types to generate an object with only the specified fields/properties.
Below is a simple way of doing this. You can do optimizations, like having a type cache for the reflection. But this should work for simple fields/properties.
public static object DynamicProjection(object input, IEnumerable<string> properties)
{
var type = input.GetType();
dynamic dObject = new ExpandoObject();
var dDict = dObject as IDictionary<string, object>;
foreach (var p in properties)
{
var field = type.GetField(p);
if (field != null)
dDict [p] = field.GetValue(input);
var prop = type.GetProperty(p);
if (prop != null && prop.GetIndexParameters().Length == 0)
dDict[p] = prop.GetValue(input, null);
}
return dObject;
}
Usage:
//...
var names = new[] { "Id", "Name", "Tracks" };
var projection = collection.Select(x => DynamicProjection(x, names));
//...

Retrieve Name value from ColumnAttribute for Entity Framework batch deletes

I want to implement batch delete (for performance reasons) in Entity framework like this:
context.ExecuteStoreCommand("DELETE FROM {0} WHERE {1} = {2}", tableName, columnName, columnValue);
I want to know how to get the column's name from the property.
[Column("ColumnName")]
public int PropertyName { get; set; }
I Also use EF5 with Oracle provider.
You use Reflection.
public class MyClass
{
[Column("ColumnName")]
public int PropertyName { get; set; }
}
Using Reflection:
public static string GetColumnName<T>(string propertyName)
{
string result = null;
if (string.IsNullOrWhiteSpace(propertyName))
{
throw new ArgumentNullException();
}
var tableType = typeof(T);
var properties = tableType.GetProperties(BindingFlags.GetProperty
| BindingFlags.Instance
| BindingFlags.Public);
var property = properties
.Where(p => p.Name.Equals(propertyName,
StringComparison.CurrentCultureIgnoreCase))
.FirstOrDefault();
if (property == null)
{
throw new Exception("PropertyName not found."); // bad example
}
else
{
result = property.Name; //if no column attribute exists;
var attributes = property.GetCustomAttributes();
var attribute = attributes
.Where(a => a is ColumnAttribute)
.FirstOrDefault() as ColumnAttribute;
if (attribute != null)
{
result = attribute.Name;
}
}
return result;
}
For example:
public class MyClass
{
[Column("ColumnName")]
public int PropertyName { get; set; }
}
var result = GetColumnName<MyClass>("PropertyName");
Console.WriteLine(result);
Result:
ColumnName

Can not fake guid properties using FakeO

I am trying to use the library called FakeO (https://github.com/rally25rs/FakeO)
It works fine except when there is a Guid property. Anyone have an idea what I maybe doing wrong ?
Exceptin I get is : Object of type 'System.Int32' cannot be converted to type 'System.Guid'.
here is the code
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Get a single instance of an object");
var gud = Guid.NewGuid();
var obj1 = FakeO.Create.Fake<SampleClass>(
s => s.UniqueId = FakeO.Data.Random<Guid>(),
s => s.Id = FakeO.Number.Next(),
s => s.PhoneNumber = FakeO.Phone.Number(),
s => s.SomeString = FakeO.String.Random(50));
Console.WriteLine(obj1.ToString() + "\n");
IEnumerable<SampleClass> obj2 = FakeO.Create.Fake<SampleClass>(10, s => s.Id = FakeO.Number.Next(),
s => s.PhoneNumber = FakeO.Phone.Number(),
s => s.SomeString = FakeO.String.Random(50));
foreach (var obj in obj2)
Console.WriteLine(obj.ToString());
Console.ReadKey();
}
}
public class SampleClass
{
public int Id { get; set; }
public string SomeString { get; set; }
public string PhoneNumber { get; set; }
public Guid UniqueId { get; set; }
public override string ToString()
{
var output = "ID={0},SomeString ={1},PhoneNumber = {2}";
return String.Format(output, Id, SomeString, PhoneNumber);
}
}
Guid is value type, and the author did not handle unsupported ValueType properly. He returns 0 for all unsupported value types in the Data.Random method, which is not quite nice for any struct type. According to this StackOverflow question, the last lines of Data.Random should be fixed to
if(t.IsValueType)
{
return Activator.CreateInstance(t);
}
return null;
This will return default value for struct type, which is empty Guid in case of Guid type I believe. If you want to support Guid type, you can add it in Data.Random method just before the final check of ValueType:
if (t == typeof(Guid))
return Guid.NewGuid();
I did not test my solution, but it should do.
It looks like you should be using:
FakeO.Distinct.Guid()

Categories