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.
Related
I am getting a Parameter Count mismatch error which I don't understand.
I have the below code:
Type target = Type.GetType("CPS_Service." + DocumentType);
// Create an instance of my target class
instance = Activator.CreateInstance(target);
foreach (XElement pQ in PQData.Elements())
{
try
{
// populate the member in the instance of the data class with the value from the MQ String
if (target.GetProperty(pQ.Attribute("name").Value) != null)
{
target.GetProperty(pQ.Attribute("name").Value).SetValue(instance, pqRequest[Convert.ToInt32(pQ.Attribute("pos").Value)], null);
}
}
}
PropertyInfo[] properties = target.GetProperties();
foreach (PropertyInfo property in properties)
{
DataColumn col = new DataColumn(property.Name);
col.DataType = System.Type.GetType("System.String");
col.DefaultValue = "";
dt.Columns.Add(col);
}
DataRow dr = dt.NewRow();
foreach (PropertyInfo property in properties)
{
string value = property.GetValue(instance).ToString();
dr[property.Name.ToString()] = "";
}
dt.Rows.Add(dr);
return dt; //
so I am instantiating a generic class and populating it from a string array (taken from a tab-delimited string), then I need to either output a List or a datatable from the class instance
When populating the datarow dr for my datatable dt I am trying to get the value from the class:
string value = property.GetValue(instance, null).ToString();
dr[property.Name.ToString()] = "";
but on the line property.GetValue(instance).ToString(); I get the below error:
Parameter count mismatch
I have searched around and the other questions about this error do not apply...
Or would I be better off just casting my class to a List and returning that?
If you're trying to get the value of all properties of a String (or any type that has an indexer), then you're going to have to have a special case to deal with the indexer. So if you wanted to get the value of that parameter you'd have to pass the object array of values with one parameter as the index value you wanted to get.
For example, property.GetValue(test, new object [] { 0 }); would get the value of the string at index 0. So if the string's value was "ABC", the result of would be 'A'.
The easiest thing would be just to skip the indexer. You can test if a property is an indexer by using property.GetIndexParameters().Any(). I thought you could skip this check by using the appropriate binding flag when calling GetProperties(), but if you can, I didn't see it.
If you want to skip the index in your code, then change:
PropertyInfo[] properties = target.GetProperties();
To:
var properties = target.GetProperties().Where(p => !p.GetIndexParameters().Any());
I created an extension method to convert a datatable to list and list to datatable. I have multiple problems with this. can someone help me fix the issues please:
Both datatable columns and the generic class property names needs to be the same even and case sensitive. I need to modify this to handle the situation where case is not taken into consideration ex: EmployeeName = employeename.
If the generic class has a complex type as a property then my function does not seem to work. ex: if i have Public string EmployeeName {get; set;} my code works, but if i have Public Department DepartmentDetails {get; set;} ( know this one is a bit tricky but if someone can give me a suggestion how to handle this at all, i shall be glad.)
Please find below my Extension method.
public static List<T> ToList<T>(this DataTable table) where T : new()
{
try
{
var dataList = new List<T>();
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
var propertyList = (from PropertyInfo property in typeof(T).GetProperties(flags)
select new
{
Name = property.Name,
Type = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType
}).ToList();
var dataTableFieldNames = (from DataColumn columnHeader in table.Columns
select new { Name = columnHeader.ColumnName, Type = columnHeader.DataType }).ToList();
var commonProperties = propertyList.Intersect(dataTableFieldNames).ToList();
foreach (DataRow dataRow in table.AsEnumerable().ToList())
{
var templateType = new T();
foreach (var field in commonProperties)
{
PropertyInfo propertyInfos = templateType.GetType().GetProperty(field.Name);
propertyInfos.SetValue(templateType, dataRow[field.Name], null);
}
dataList.Add(templateType);
}
return dataList;
}
catch (Exception ex)
{
throw;
}
}
Any help is highly appreciated. Cheers!!!
Both datatable columns and the generic class property names needs to be the same even and case sensitive. I need to modify this to handle the situation where case is not taken into consideration ex: EmployeeName = employeename.
That part is easy. You can compare the Name's case-insensitively:
var commonProperties = propertyList
.Where(p => dataTableFieldNames
.Any(d => string.Equals(d.Name, p.Name, StringComparison.OrdinalIgnoreCase) &&
d.Type == p.Type).ToList();
If the generic class has a complex type as a property then my function does not seem to work.
Now that is a bit hard and depends on what would you like to do in that situation? Does your DataTable also contains columns that belongs the other types (e.g. Departmant) ? If so you will need to determine which types of properties you have (additionally,other than the built-in types) and which additional columns exists in your DataTable for those types.Then you can get the properties of each type and map them to the columns in your DataTable.
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.
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.
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