Generic search implementation in EF Core - c#

I'm trying to implement a generic search method which can be used with all entities of DB.
public static object HandleSearch(object objList, string searchText)
{
Dictionary<string, object> ht = null;
List<Dictionary<string, object>> returnList = new List<Dictionary<string, object>>();
var a = objList as ICollection;
object data = null;
Type tp = null;
foreach (object obj in a)
{
ht = (Dictionary<string, object>)obj;
foreach (string key in ht.Keys)
{
data = ht[key];
tp = data.GetType();
if (tp == typeof(DateTime))
{
if (((DateTime)data).ToString("dd/MM/yyyy HH:mm:ss").Contains(searchText))
{
returnList.Add(ht);
break;
}
else if (data.ToString().ToLower().Contains(searchText.ToLower()))
{
returnList.Add(ht);
break;
}
}
}
}
return returnList;
}
I should call this as
var x = _service.GetAll(eo);
var c = GeaUtility.HandleSearch(x, "29/02");
When I try it gives me "unable to cast from List to List<Dictionary<string, object>>.
How can I solve? Any ideas?

Related

Get generic list from object (over reflection)

I query some data via reflection. The returned data type is System.data.datacolumn[] (variable "test"). I would like to convert it into a generic list (e.g. string List). Is that possible?
public IEnumerable<string> GetStringList(string property)
{
var test = GetPropertyValue(SomeObject, property);
// MAGIC //
return test;
}
public object GetPropertyValue(object obj, string propertyName)
{
var propertyNames = propertyName.Split('.');
foreach (var t in propertyNames)
{
if (obj != null)
{
var propertyInfo = obj.GetType().GetProperty(t);
obj = propertyInfo != null ? propertyInfo.GetValue(obj) : null;
}
}
return obj;
}
you can try this
if (test is IEnumerable) {
var values = test as IEnumerable;
//Method 1: convert to list
var asList = values.Cast<object>().ToList();
//Method 2: iterate to IEnumerable and add to List
var asList = new List<object>();
foreach (var value in values)
{
asList.Add(value);
}
}

create objects from properties in string

object with additional properties from json-like notation string should created.
Method will called from Razor view to pass colmodel to jqgrid
as json object like
#Html.Raw( Json.Encode( Model.GetColModel()))
Method should have signature like
object GetColModel(string colName, int colWidth, string additonalProperties)
For example,
GetColModel("customer", 17, "address=\"Toronto\", index=1555" )
should return object
new { colName="customer", colwidth=17, address="Toronto", index=1555 }
There may be nested properties like in JSON, eq.
GetColModel("customer", 17, "formatoptions= new { formatter=\"number\", editable=true } " )
should return object
new { colName="customer", colwidth=17, formatoptions=new {
formatter="number",
editable=true
}
}
I tried method
public object GetColModel(string colName, int colWidth, string additonalProperties)
{
return new
{
name = colName,
width = colWidth,
&addtitionalProperties
};
}
but this fails since macros are not supported in C#
How to create such method or other way to add properties from database to json strung in Razor view ?
It is called from ASP.NET/Mono C# MVC 4 viewmodel.
Razor views and RazorEngine are used.
There is nothing built in to do this, but you parse your string using string (string.Split will let you split on ',' but if you might have those in your text you will have to build a real parser, or switch you string format to something like CSV where you can find lots of parsers out there. You might be able to find a property parser for simple syntax. Or you push your additional properties string as json and use Json.net to parse.
Once you have your string parsed into a key/value structure, then you can use ExpandoObject to populate your final object and return that.
https://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject(v=vs.110).aspx
Here is a naive implementation of a true json based solution.
You can invoke it using:
dynamic d = Model.GetColModel("customer", 17, " { formatoptions : { formatter : \"number\", editable :true }, stam :2}");
Implementation:
static class ModelExtension
{
public static dynamic GetColModel(this Model model, string colName, int colWidth, string additonalProperties) {
dynamic expando = new ExpandoObject();
var json = JsonConvert.DeserializeObject<JObject>(additonalProperties);
expando.name = colName;
expando.width = colWidth;
return new FromPropertiesDynamicObjectCreator(expando, json);
}
private class FromPropertiesDynamicObjectCreator : DynamicObject
{
private readonly dynamic expando = null;
public FromPropertiesDynamicObjectCreator(IDictionary<string, object> expando, JObject props = null) {
this.expando = expando;
if (props != null) {
((dynamic)this).props = props;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
if (binder.Name.Equals("props")) {
var jsonObj = value as JObject;
JToken current = jsonObj.First;
var dictionary = expando as IDictionary<string, object>;
RecurseJson(current, dictionary);
return true;
}
return false;
}
private void RecurseJson(JToken current, IDictionary<string, object> dictionary) {
JToken value;
Dictionary<string, object> newDictionary;
while (current != null) {
var children = current.Children().ToList();
foreach (var child in children) {
switch (child.Type) {
case JTokenType.Object:
case JTokenType.Array:
newDictionary = new Dictionary<string, object>();
dictionary[child.Path] = newDictionary;
RecurseJson(child, newDictionary);
break;
case JTokenType.Property:
var prop = ((JProperty)child);
value = prop.Value;
if (value.HasValues) {
newDictionary = new Dictionary<string, object>();
dictionary[prop.Name] = newDictionary;
RecurseJson(child, newDictionary);
break;
}
dictionary[prop.Name] = ((dynamic)value).Value;
break;
default:
var val = ((dynamic)child).Value;
if (val is JToken) {
dictionary[child.Path] = val.Value;
}
else {
dictionary[child.Path] = val;
}
break;
}
}
current = current.Next;
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
object value;
var dictionary = expando as IDictionary<string, object>;
if (dictionary.TryGetValue(binder.Name, out value)) {
var innerDictionary = value as IDictionary<string, object>;
if (innerDictionary != null) {
result = new FromPropertiesDynamicObjectCreator(innerDictionary);
}
else {
result = value;
}
return true;
}
result = null;
return true;
}
}
}

SetValue with generic type T

I have this function:
the variable c obtains all the properties of my class <T>
in this case:
c ->
Id
Key
Value
public List<T> ReadStoreProceadure<T>(string storeName)
{
var result = new List<T>();
var instance = (T) Activator.CreateInstance(typeof (T), new object[] {});
var c = typeof (T);
var data = DataReader.ReadStoredProceadures(_factibilidad, storeName); // This part is returning verified data and it's ok
while (data.Read())
{
if (data.HasRows)
{
foreach (var item in c.GetProperties())
{
//item.SetValue(c, item.Name, null);
}
}
}
}
How I can add these values to my instance instance and add it to my result variable?
It's possible?
I've created an extension method for IDataReader that does essentially what I believe you're trying to do:
public static List<T> ToList<T>(this IDataReader dr) where T: new()
{
var col = new List<T>();
var type = typeof(T);
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
while (dr.Read())
{
var obj = new T();
for (int i = 0; i < dr.FieldCount; i++)
{
string fieldName = dr.GetName(i);
var prop = props.FirstOrDefault(x => x.Name.ToLower() == fieldName.ToLower());
if (prop != null)
{
if (dr[i] != DBNull.Value)
{
prop.SetValue(obj, dr[i], null);
}
}
}
col.Add(obj);
}
dr.Close();
return col;
}
However, you'll notice I've chosen to work the from the other way around. Instead of iterating the type's properties and fetching them from the DataReader, I iterate the DataReader columns and check for a matching property on the type. You should be able to quickly modify this to fit your data retrieval scheme.

How to convert object to Dictionary<TKey, TValue> in C#?

How do I convert a dynamic object to a Dictionary<TKey, TValue> in C# What can I do?
public static void MyMethod(object obj)
{
if (typeof(IDictionary).IsAssignableFrom(obj.GetType()))
{
// My object is a dictionary, casting the object:
// (Dictionary<string, string>) obj;
// causes error ...
}
else
{
// My object is not a dictionary
}
}
The above answers are all cool. I found it easy to json serialize the object and deserialize as a dictionary.
var json = JsonConvert.SerializeObject(obj);
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
I don't know how performance is effected but this is much easier to read. You could also wrap it inside a function.
public static Dictionary<string, TValue> ToDictionary<TValue>(object obj)
{
var json = JsonConvert.SerializeObject(obj);
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, TValue>>(json);
return dictionary;
}
Use like so:
var obj = new { foo = 12345, boo = true };
var dictionary = ToDictionary<string>(obj);
I use this helper:
public static class ObjectToDictionaryHelper
{
public static IDictionary<string, object> ToDictionary(this object source)
{
return source.ToDictionary<object>();
}
public static IDictionary<string, T> ToDictionary<T>(this object source)
{
if (source == null)
ThrowExceptionWhenSourceArgumentIsNull();
var dictionary = new Dictionary<string, T>();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
AddPropertyToDictionary<T>(property, source, dictionary);
return dictionary;
}
private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary)
{
object value = property.GetValue(source);
if (IsOfType<T>(value))
dictionary.Add(property.Name, (T)value);
}
private static bool IsOfType<T>(object value)
{
return value is T;
}
private static void ThrowExceptionWhenSourceArgumentIsNull()
{
throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
}
}
the usage is just to call .ToDictionary() on an object
Hope it helps.
public static KeyValuePair<object, object > Cast<K, V>(this KeyValuePair<K, V> kvp)
{
return new KeyValuePair<object, object>(kvp.Key, kvp.Value);
}
public static KeyValuePair<T, V> CastFrom<T, V>(Object obj)
{
return (KeyValuePair<T, V>) obj;
}
public static KeyValuePair<object , object > CastFrom(Object obj)
{
var type = obj.GetType();
if (type.IsGenericType)
{
if (type == typeof (KeyValuePair<,>))
{
var key = type.GetProperty("Key");
var value = type.GetProperty("Value");
var keyObj = key.GetValue(obj, null);
var valueObj = value.GetValue(obj, null);
return new KeyValuePair<object, object>(keyObj, valueObj);
}
}
throw new ArgumentException(" ### -> public static KeyValuePair<object , object > CastFrom(Object obj) : Error : obj argument must be KeyValuePair<,>");
}
From the OP:
Instead of converting my whole Dictionary, i decided to keep my obj
dynamic the whole time. When i access the keys and values of my
Dictionary with a foreach later, i use foreach(dynamic key in
obj.Keys) and convert the keys and values to strings simply.
Another option is to use NewtonSoft.JSON.
var dictionary = JObject.FromObject(anObject).ToObject<Dictionary<string, object>>();
If you don't mind LINQ Expressions;
public static Dictionary<string, object> ConvertFromObjectToDictionary(object arg)
{
return arg.GetType().GetProperties().ToDictionary(property => property.Name, property => property.GetValue(arg));
}
this should work:
for numbers, strings, date, etc.:
public static void MyMethod(object obj)
{
if (typeof(IDictionary).IsAssignableFrom(obj.GetType()))
{
IDictionary idict = (IDictionary)obj;
Dictionary<string, string> newDict = new Dictionary<string, string>();
foreach (object key in idict.Keys)
{
newDict.Add(key.ToString(), idict[key].ToString());
}
}
else
{
// My object is not a dictionary
}
}
if your dictionary also contains some other objects:
public static void MyMethod(object obj)
{
if (typeof(IDictionary).IsAssignableFrom(obj.GetType()))
{
IDictionary idict = (IDictionary)obj;
Dictionary<string, string> newDict = new Dictionary<string, string>();
foreach (object key in idict.Keys)
{
newDict.Add(objToString(key), objToString(idict[key]));
}
}
else
{
// My object is not a dictionary
}
}
private static string objToString(object obj)
{
string str = "";
if (obj.GetType().FullName == "System.String")
{
str = (string)obj;
}
else if (obj.GetType().FullName == "test.Testclass")
{
TestClass c = (TestClass)obj;
str = c.Info;
}
return str;
}
public static void MyMethod(object obj){
Dictionary<string, string> dicEditdata = data as Dictionary<string, string>;
string abc=dicEditdata["id"].ToString();}
suppose---
if you place the cursor over the object(obj) while debugging and
if you get an object with the value {['id':'ID1003']}
then you can use the value as
string abc=dicEditdata["id"].ToString();
Assuming key can only be a string but value can be anything try this
public static Dictionary<TKey, TValue> MyMethod<TKey, TValue>(object obj)
{
if (obj is Dictionary<TKey, TValue> stringDictionary)
{
return stringDictionary;
}
if (obj is IDictionary baseDictionary)
{
var dictionary = new Dictionary<TKey, TValue>();
foreach (DictionaryEntry keyValue in baseDictionary)
{
if (!(keyValue.Value is TValue))
{
// value is not TKey. perhaps throw an exception
return null;
}
if (!(keyValue.Key is TKey))
{
// value is not TValue. perhaps throw an exception
return null;
}
dictionary.Add((TKey)keyValue.Key, (TValue)keyValue.Value);
}
return dictionary;
}
// object is not a dictionary. perhaps throw an exception
return null;
}
I've done something like this and works for me.
using System.ComponentModel;
var dictionary = new Dictionary<string, string>();
foreach (var propDesc in TypeDescriptor.GetProperties(Obj))
{
if (!string.IsNullOrEmpty(propDesc.GetValue(Obj)))
{
dictionary.Add(propDesc.Name, propDesc.GetValue(Obj));
}
}
Also, another alternative and innovative solution is here.
var dictionary = new System.Web.Routing.RouteValueDictionary(Obj);
I hope this could work :)
// obj = new { a = "string", b = 0, c = true };
static Dictionary<string, object> ToDictionary(object obj)
{
int i = 0;
var props = obj.GetType().GetProperties();
return props.ToDictionary(k => props[i].Name, v => props[i++].GetValue(obj));
}
This code securely works to convert Object to Dictionary (having as premise that the source object comes from a Dictionary):
private static Dictionary<TKey, TValue> ObjectToDictionary<TKey, TValue>(object source)
{
Dictionary<TKey, TValue> result = new Dictionary<TKey, TValue>();
TKey[] keys = { };
TValue[] values = { };
bool outLoopingKeys = false, outLoopingValues = false;
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
{
object value = property.GetValue(source);
if (value is Dictionary<TKey, TValue>.KeyCollection)
{
keys = ((Dictionary<TKey, TValue>.KeyCollection)value).ToArray();
outLoopingKeys = true;
}
if (value is Dictionary<TKey, TValue>.ValueCollection)
{
values = ((Dictionary<TKey, TValue>.ValueCollection)value).ToArray();
outLoopingValues = true;
}
if(outLoopingKeys & outLoopingValues)
{
break;
}
}
for (int i = 0; i < keys.Length; i++)
{
result.Add(keys[i], values[i]);
}
return result;
}
This way for object array to Dictionary<string, object> List coverting
object[] a = new object[2];
var x = a.Select(f => (Dictionary<string, object>)f).ToList();
This way for single object to Dictionary<string, object> coverting
object a = new object;
var x = (Dictionary<string, object>)a;
You can create a generic extension method and then use it on the object like:
public static class Extensions
{
public static KeyValuePair<TKey, TValue> ToKeyValuePair<TKey, TValue>(this Object obj)
{
// if obj is null throws exception
Contract.Requires(obj != null);
// gets the type of the obj parameter
var type = obj.GetType();
// checks if obj is of type KeyValuePair
if (type.IsGenericType && type == typeof(KeyValuePair<TKey, TValue>))
{
return new KeyValuePair<TKey, TValue>(
(TKey)type.GetProperty("Key").GetValue(obj, null),
(TValue)type.GetProperty("Value").GetValue(obj, null)
);
}
// if obj type does not match KeyValuePair throw exception
throw new ArgumentException($"obj argument must be of type KeyValuePair<{typeof(TKey).FullName},{typeof(TValue).FullName}>");
}
and usage would be like:
KeyValuePair<string,long> kvp = obj.ToKeyValuePair<string,long>();
I use this simple method:
public Dictionary<string, string> objToDict(XYZ.ObjectCollection objs) {
var dict = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> each in objs){
dict.Add(each.Key, each.Value);
}
return dict;
}
You can use this:
Dictionary<object,object> mydic = ((IEnumerable)obj).Cast<object>().ToList().ToDictionary(px => px.GetType().GetProperty("Key").GetValue(px), pv => pv.GetType().GetProperty("Value").GetValue(pv));
string BaseUrl = "http://www.example.com";
HttpClient client = new HttpClient { BaseAddress = new Uri(BaseUrl) };
PropertyInfo[] properties = object.GetType().GetProperties();
Dictionary<string, string> dictionary = new Dictionary<string, string>();
foreach (PropertyInfo property in properties)
{
dictionary.Add(property.Name, property.GetValue(model, null).ToString());
}
foreach (string key in dictionary.Keys)
{
client.DefaultRequestHeaders.Add(key, dictionary[key]);
}
As I understand it, you're not sure what the keys and values are, but you want to convert them into strings?
Maybe this can work:
public static void MyMethod(object obj)
{
var iDict = obj as IDictionary;
if (iDict != null)
{
var dictStrStr = iDict.Cast<DictionaryEntry>()
.ToDictionary(de => de.Key.ToString(), de => de.Value.ToString());
// use your dictStrStr
}
else
{
// My object is not an IDictionary
}
}
object parsedData = se.Deserialize(reader);
System.Collections.IEnumerable stksEnum = parsedData as System.Collections.IEnumerable;
then will be able to enumerate it!
Simple way:
public IDictionary<T, V> toDictionary<T, V>(Object objAttached)
{
var dicCurrent = new Dictionary<T, V>();
foreach (DictionaryEntry dicData in (objAttached as IDictionary))
{
dicCurrent.Add((T)dicData.Key, (V)dicData.Value);
}
return dicCurrent;
}

Getting all keys and their values from ObjectStateEntry in Entity Framework

For audit logging purpose I override SaveChanges() method in EF 4.1 Database-First approach .
I have all ObjectStateEntry object and I'm wondering if I could get all keys and their values from each ObjectStateEntry .
IEnumerable<ObjectStateEntry> changes = this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified);
foreach (ObjectStateEntry stateEntryEntity in changes)
{
if (!stateEntryEntity.IsRelationship &&
stateEntryEntity.Entity != null &&
!(stateEntryEntity.Entity is DBAudit))
{
list<object , object> KeyValues = GetAllKeyValues(stateEntryEntity );
//Do log all keyvalues
}
}
I haven't tested it but something like this should work:
private Dictionary<string, object> GetAllKeyValues(ObjectStateEntry entry)
{
var keyValues = new Dictionary<string, object>();
var currentValues = entry.CurrentValues;
for (int i = 0; i < currentValues.FieldCount; i++)
{
keyValues.Add(currentValues.GetName(i), currentValues.GetValue(i));
}
return keyValues;
}
Try using ObjectStateEntry.EntityKey and EntityKey.EntityKeyValues:
var keyValues = stateEntityEntry.EntityKey.EntityKeyValues;
which returns an array of EntityKeyMember. You can then use the Key and Value properties, which return a string and object respectively.
Here is my solution in the form of an extension method.
public static class ExtensionMethods
{
public static IReadOnlyDictionary<string, object> GetKeyValues(this ObjectStateEntry instance)
{
var keyMemberNames = instance
.EntitySet
.ElementType
.KeyMembers
.Select(x => x.Name)
.ToList();
var currentValues = instance.CurrentValues;
var result = new Dictionary<string, object>();
for (var i = 0; i < currentValues.FieldCount; i++)
{
var name = currentValues.GetName(i);
if (!keyMemberNames.Contains(name))
continue;
var value = currentValues.GetValue(i);
result.Add(name, value);
}
return result;
}
public static IReadOnlyDictionary<string, object> GetValues(this ObjectStateEntry instance)
{
var currentValues = instance.CurrentValues;
var result = new Dictionary<string, object>();
for (var i = 0; i < currentValues.FieldCount; i++)
{
var name = currentValues.GetName(i);
var value = currentValues.GetValue(i);
result.Add(name, value);
}
return result;
}
}

Categories

Resources