Looping through the properties of an IQueryable - c#

Let's say I have an IQueryable with a bunch of properties obtained through LINQ, how can I loop through these properties?
I have tried:
foreach (PropertyInfo propertyInfo in rows.GetType().GetProperties())
{
var value = propertyInfo.GetValue(this, null);
var name = propertyInfo.Name;
}
This doesn't seem to work though and nothing is returned. I need a way to retrieve the name of values of all properties inside of the IQueryable.

If rows is the result of the query, you'd need to use Type.GetGenericArguments:
var type = rows.GetType().GetGenericArguments().First();
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
//...
This is because the result will be an IQueryable<T>, not the value itself. Extracting out the generic type will likely allow you to get the properties explicitly.

Related

Convert datatable object to list C#

I have found below code on stackoverflow. But i am not getting what fundamentally this code is doing. Can anyone please explain me how this code works?
public static List<T> ToListof<T>(DataTable dt)
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
var columnNames = dt.Columns.Cast<DataColumn>()
.Select(c => c.ColumnName)
.ToList();
var objectProperties = typeof(T).GetProperties(flags);
var targetList = dt.AsEnumerable().Select(dataRow =>
{
var instanceOfT = Activator.CreateInstance<T>();
foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
{
properties.SetValue(instanceOfT, dataRow[properties.Name], null);
}
return instanceOfT;
}).ToList();
return targetList;
}
Specially i want to know at where coloumn's data is getting type casted. I have searched on many links but i am not getting proper answer anywhere.
It attempts to convert a datatable to a list of objects of type T, dynamically at runtime.
var objectProperties = typeof(T).GetProperties(flags);
This line uses Reflection to get a list of public properties on type T.
var targetList = dt.AsEnumerable().Select(dataRow =>
This line iterates the DataTable as an IEnumerable, getting an instance called dataRow for each row.
var instanceOfT = Activator.CreateInstance<T>();
This creates a new instance of type T using reflection, inside the loop. This means a new T is created for each dataRow.
foreach (var properties in objectProperties.Where(properties =>
columnNames.Contains(properties.Name)
This goes over all the properties of T we got back in the beginning, which are also in columnNames - meaning that there's a column with value for them
&& dataRow[properties.Name] != DBNull.Value))
The second half of the condition makes sure that the column has a value and isn't NULL.
properties.SetValue(instanceOfT, dataRow[properties.Name], null);
This uses reflection, again to set the value from the datarow into the property of T.
).ToList();
This takes all the items returned from the Select statement and returns a List from them.
The code isn't the neatest, but the variables are pretty well-named and clear, if you know how reflection works. As for your second question - there's no casting, because this code assumes that the type of the value in the DataRow matches the type of the property. If it doesn't, an exception will be thrown.
In Detail:
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
this will combine the public and the instance flag so that only Public non static methods will be searched.
var columnNames = dt.Columns.Cast<DataColumn>()
.Select(c => c.ColumnName)
.ToList();
this will list all column names from the data table
var objectProperties = typeof(T).GetProperties(flags);
gets the Type of the generic argument and will list all public, non static properties
dt.AsEnumerable().Select
creates an IEnumerable of each data row in the DataTable
var instanceOfT = Activator.CreateInstance<T>();
this creates a new instance as you would use new
foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
{
properties.SetValue(instanceOfT, dataRow[properties.Name], null);
}
this will iterate through all propertys of T whos also contained in the datatable and not null (eg. DbNull from the database)
then it calls SetValue. As the dataRow will already return the value as its stored in the database there is no cast nessesary. This does only work if the Property and the type in the database are "the same". As NVarchar for string.

Getting a PropertyInfo of a dynamic object

I have a library that is doing a bunch of reflection work relying on the PropertyInfo of the classes it receives (to get and set values).
Now I want to be able to work with dynamic objects, but I can't find how to get the PropertyInfo of a dynamic's properties. I've checked the alternatives, but for those I'd need to change everywhere I use PropertyInfo to get/set values.
dynamic entity = new ExpandoObject();
entity.MyID = 1;
// - Always null
PropertyInfo p = entity.GetType().GetProperty("MyID");
// - Always null
PropertyInfo[] ps = entity.GetType().GetProperties();
// - These are called everywhere in the code
object value = p.GetValue(entity);
p.SetValue(entity, value);
Is it possible to get or create a PropertyInfo somehow just to be able to use it's GetValue() and SetValue() on a dynamic object?
Under the covers an ExpandoObject is really just a dictionary. You can get at the dictionary just by casting it.
dynamic entity = new ExpandoObject();
entity.MyID = 1;
if(entity.GetType() == typeof(ExpandoObject))
{
Console.WriteLine("I'm dynamic, use the dictionary");
var dictionary = (IDictionary<string, object>)entity;
}
else
{
Console.WriteLine("Not dynamic, use reflection");
}
You could modify your Mapping method to check if the object being passed in is dynamic and route through a different path that just iterates over the keys of the dictionary.
https://dotnetfiddle.net/VQQZdy

Attempting to obtain properties / fields from an (anonymous class) object linq is creating

I'm having trouble figuring out what I'm doing wrong here. I have some LINQ that returns an IQuery object, and later in the code, I'm attempting to list out the attributes returned. This is best explained by this abbreviated code (the actual LINQ is a lot more complex and involves joins - the LINQ itself works fine):
public IQueryable<Object> FindAll()
{
var query = from user in _db.Users
select new
{
id = user.Id,
is_active = user.IsActive,
email = user.Email,
dob = user.Dob,
user.user_type,
};
return query;
}
Elsewhere in the code I have:
query.ConvertToCsv();
Although I have attempted to insert a .ToList() in that call as well.
The ConvertToCsv has:
public static string ConvertToCSV<TSource>(this IEnumerable<TSource> source)
{
StringBuilder sb = new StringBuilder();
var properties = typeof(TSource).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
var enumerable = source as IList<TSource> ?? source.ToList();
if (!enumerable.Any()) return "";
string headerString = "";
foreach (var prop in properties)
{
headerString += (headerString.Length > 0 ? "," : "") + prop.Name;
}
sb.AppendLine(headerString);
foreach (TSource item in enumerable)
{
string line = string.Join(",", properties.Select(p => p.GetValue(item).ToCsvValue()).ToArray());
sb.AppendLine(line);
}
return sb.ToString();
}
Note I have also tried to pull out the property names with this code:
PropertyInfo[] pi = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
var properties = pi.OrderBy(x => x.MetadataToken);
foreach (PropertyInfo p in properties)
{ etc etc }
In all cases, the property or field list returns an empty list, and as such, I can't iterate through the object to spit out a header row or data rows. Tracing through all the code and inspecting the variables indicates that everything is fine until I get to the GetProperties/GetFields line and the code fails.
What rookie mistake am I making? Should I be replacing <Object> with something else?
To pass an anonymous type, or a collection that contains anonymous
types, as an argument to a method, you can declare the parameter as
type object. However, doing this defeats the purpose of strong typing.
If you must store query results or pass them outside the method
boundary, consider using an ordinary named struct or class instead of
an anonymous type.
by Anonymous Types (C# Programming Guide)
Create your own class and change method declaration to be IQueryable<MyClass> instead of object
Did you consider doing something like: db.Users.Select(u => new UserDto() { Id = user.Id, Name = ..., where UserDto is dedicated class that has all the properties you'll need in the future? I think you lose information about properties when you cast from anonymous class to an Object. Although, I never tried to obtain member info from anonymous class

Using reflection to create an object represented by the contents of a "Type" object

I am using reflection to find a type by a string like this...
Type currentType = Type.GetType(typeName);
I then am able to get a list of properties for that type like this...
var props = currentType.GetProperties();
How do I instantiate a new object of this type and then start assigning values to the properties of that object based on the list of properties in the props list?
Using the values you already have...
var created = Activator.CreateInstance(currentType);
foreach(var prop in props)
{
prop.SetValue(created, YOUR_PROPERTY_VALUE, null);
}
Instantiate the currentType with:
var newInst = Activator.CreateInstance(currentType);
and assign property values with:
propInfo.SetValue(newInst, propValue, BindingFlags.SetProperty, null, null, null);
Where propInfo is the PropertyInfo instance from your props and propValue is the object you want to assign to the property.
EDIT:
I always lean towards using the more verbose SetValue overload because I've had problems with the short one in the past, but propInfo.SetValue(newInst, propValue, null); might work as well.

Dynamic Lambda with all properties of a property of an object

I had asked a question on how to dynamically compile a LINQ query with all the properties of an object and houlgap had been kind enough to give me the following code
private static Func<MyEntity, bool> GenerateLambda(MyEntity _myEntity, PropertyInfo propertyInfo)
{
var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
var property = Expression.Property(instance, propertyInfo);
var propertyValue = Expression.Constant(propertyInfo.GetValue(_myEntity, null));
var equalityCheck = Expression.Equal(property, propertyValue);
return Expression.Lambda<Func<MyEntity, bool>>(equalityCheck, instance).Compile();
}
This works great if the property to be queried is directly a member of the object but for me there is an intermediate property in between. For e.g. The Func Delegate is for another type e.g. Func<ABCMyEntity,bool> while the MyEntity is a member of this object (ABCMyEntity.MyEntity). The Propertyinfo object which is passed is a member of MyEntity.
I know it sounds terribly confusing but I am not able to better explain it. (Maybe because I am not a native speaker). Please ask me if something is not clear in the question.
It is continued from Constructing Dynamic LINQ queries with all properties of an object
If you need to access a chain of properties (e.g. v.MyEntity.OtherProperty) then you can just call Expression.Property multiple times:
var prop1 = // first property
var prop2 = // second property
// Variable has type of the declarating type of the 1st property
var instance = Expression.Parameter(prop1.DeclaringType, "i");
// Get first property on the 'instance'
var expr1 = Expression.Property(instance, prop1);
// Get second property on the previous expression
var expr2 = Expression.Property(expr, prop2);
// The rest of the code stays the same (only use 'expr2')
var propertyValue = Expression.Constant(propertyInfo.GetValue(_myEntity, null));
var equalityCheck = Expression.Equal(expr2, propertyValue);
return Expression.Lambda<Func<MyEntity, bool>>
(equalityCheck, instance).Compile();
If you need to access more than just two properties, you can easily turn the part that calls Expression.Property into a loop - you would just iterate over a list of desired properties and add property access to the expression using Expression.Property.

Categories

Resources