Create distinct expando object list - c#

I have created a method which will create dynamic object list from an object list according to property list. In this case I have completed such task using Expandoobject. But I have failed to create distinct list of such expando object list. Please visit the following fidder and see my code.
public class Program
{
public static void Main()
{
var _dynamicObjectList = new List<Student>();
for (int i = 0; i < 5; i++)
{
_dynamicObjectList.Add(new Student { ID = i, Name = "stu" + i, Address = "address" + i, AdmissionDate = DateTime.Now.AddDays(i) , Age=15, FatherName="Jamal"+i, MotherName = "Jamila"+i});
}
//create again for checking distinct list
for (int i = 0; i < 5; i++)
{
_dynamicObjectList.Add(new Student { ID = i, Name = "stu" + i, Address = "address" + i, AdmissionDate = DateTime.Now.AddDays(i), Age = 15, FatherName = "Jamal" + i, MotherName = "Jamila" + i });
}
// var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,Name,Address");
// var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,FatherName,Address");
var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,Name,FatherName,MotherName,Age");
string strSerializeData = JsonConvert.SerializeObject(returnList);
Console.WriteLine(strSerializeData);
Console.ReadLine();
}
}
public class Student
{
public int? ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public DateTime AdmissionDate { get; set; }
public string FatherName { get; set; }
public string MotherName { get; set; }
public int Age { get; set; }
}
public static class test2
{
public static IList GetDdlData<T>(this IEnumerable<T> source, string userParams)
{
try
{
List<string> otherProperties = userParams.Split(',').ToList();
Dictionary<string, PropertyInfo> parentPropertyInfo = new Dictionary<string, PropertyInfo>();
Dictionary<string, Type> parentType = new Dictionary<string, Type>();
var dynamicObjectList = (from k in source select k).ToList();
if (dynamicObjectList.Count() > 0)
{
//if parentField exists then system will handle parent property
if (otherProperties.Count > 0)
{
foreach (string otherProperty in otherProperties)
{
//get parent field property info
PropertyInfo _info = dynamicObjectList[0].GetType().GetProperty(otherProperty);
parentPropertyInfo.Add(otherProperty, _info);
//get parent field propertyType
Type pType = Nullable.GetUnderlyingType(_info.PropertyType) ?? _info.PropertyType;
parentType.Add(otherProperty, pType);
}
}
}
//return List
IList<object> objList = new List<object>();
foreach (T obj in source)
{
var dynamicObj = new ExpandoObject() as IDictionary<string, Object>;
foreach (string otherProperty in otherProperties)
{
PropertyInfo objPropertyInfo = parentPropertyInfo.FirstOrDefault(m => m.Key == otherProperty).Value;
Type objPropertyType = parentType.FirstOrDefault(m => m.Key == otherProperty).Value;
Object data = (objPropertyInfo.GetValue(obj, null) == null) ? null : Convert.ChangeType(objPropertyInfo.GetValue(obj, null), objPropertyType, null);
dynamicObj.Add(otherProperty, data);
}
objList.Add(dynamicObj);
}
var returnUniqList = objList.Distinct().ToList();
return returnUniqList;
}
catch (Exception ex)
{
throw ex;
}
}
}
https://dotnetfiddle.net/hCuJwD

Just add the following code in the code block.
foreach(var objTemp in objList) {
bool isNotSimilar = true;
foreach(string property in otherProperties) {
//get sending object property data
object tempFValue = (objTemp as IDictionary < string, Object > )[property];
//get current object property data
object tempCValue = (dynamicObj as IDictionary < string, Object > )[property];
if (!tempFValue.Equals(tempCValue)) {
isNotSimilar = false;
break;
}
}
if (isNotSimilar) {
isDuplicate = true;
break;
}
}
DOTNETFIDDLE

Related

Mapping classes with reflection

I have 2 classes User and UserDto both have a Phones property, all the other properties I can map perfectly.
But the problem occurs with the Phones list of the User class, since being null, I cannot identify what type of list it is.
What I need is to be able to and create a list based on its type using reflection.
var list = new List<PhoneDto>();
list.Add(new PhoneDto { Code = 1, Number = 11111111 });
list.Add(new PhoneDto { Code = 2, Number = 11111112 });
list.Add(new PhoneDto { Code = 3, Number = 11111113 });
list.Add(new PhoneDto { Code = 4, Number = 11111114 });
list.Add(new PhoneDto { Code = 5, Number = 11111115 });
var userDto=new UserDto
{
Age=18,
IsData=true,
CreationDate=DateTime.Now,
Phones =list
};
var myMapper = new MyMapper();
var user= myMapper.Map<User>(userDto);
public class User
{
public string Name { get; set; }
public DateTime CreationDate { get; set; }
public int Age { get; set; }
public bool IsData { get; set; }
public ICollection.Phone. Phones { get; set; }
}
public class UserDto
{
public string Name { get; set; }
public DateTime CreationDate { get; set; }
public int Age { get; set; }
public bool IsData { get; set; }
public List.PhoneDto. Phones { get; set; }
}
namespace CustomMapping;
public class MyMapper
{
public T Map<T>(object sourceObject)
{
if (sourceObject == null) throw new Exception("Source object is null");
var instance = Activator.CreateInstance(typeof(T));
if (instance == null) throw new Exception("Can not create de typeof(T) Instance");
var sourceType = sourceObject.GetType();
var targetType = instance.GetType();
PropertyInfo[] sourceProperties = sourceType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
PropertyInfo[] targetProperties = targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var sourceProperty in sourceProperties)
{
if (sourceProperty == null) continue;
var targetProperty = targetProperties.FirstOrDefault(p => p.Name.ToLower() == sourceProperty.Name.ToLower() && p.CanWrite);
if (targetProperty == null) continue;
var sourceValue = sourceProperty?.GetValue(sourceObject, null);
if (sourceProperty?.PropertyType == targetProperty.PropertyType)
{
instance?.GetType()?.GetProperty(sourceProperty.Name)?.SetValue(instance, sourceValue);
continue;
}
var isEnumerable = IsEnumerable(targetProperty);
if (isEnumerable)
{
//---------Here I need to map the lists---------
}
}
return (T)instance;
}
private bool IsEnumerable(PropertyInfo propertyInfo)
{
return (propertyInfo.PropertyType.GetInterfaces().Any(p => p.Name == "IEnumerable`1") && propertyInfo.PropertyType.FullName.IndexOf("System.String") < 0);
}
}
I would appreciate any help.

How to convert array collection to a dataset c#

Hi have a response class that has three models, all of a certain type...
public class AssociationResponse
{
public AssociationModel ItemDetail {get;set;}
public AssociationModel[] Children {get;set;}
public AssociationModel Parent {get; set;}
public int ErrorCode { get; set; }
public string ErrorMessage { get; set; }
}
Now i am struggling in how to convert the AssociationModel[] Children to a simple dataset, so that i can convert them into datatables and show the results in a tree diagram.. unless anybody knows of a better way?
In my code behind
public AssociationModel ItemDetail { get; set; } = new AssociationModel();
public AssociationModel Parent { get; set; } = new AssociationModel();
public AssociationModel Child { get; set; } = new AssociationModel();
public async Task LoadData(string SerialNumber)
{
try
{
GetAssociationBySerialNumberRequest request = new GetAssociationBySerialNumberRequest()
{
SerialNumber = SerialNumber
};
response = await IAssociation.AssociationGetData(request);
AssociationResponse resp = new AssociationResponse();
if (SerialNumber != null)
{
ItemDetail = response.ItemDetail;
Parent = response.Parent;
**DataSet dset = new DataSet();**
}
}
Any help would be greatful. P.S there are three tables within my [] Children.. So i wanted to somehow access them, i have tried saving to a datatable type, but that doesn't work. any help appreciated.
Edit
The problem, i am having is that i cant seem to convert the arrays to a dataset. Not sure how to do this.
Will this work for you?
I use this extension method to convert IEnumerable to Datatables
public static DataTable ToDataTable<T>(this IList<T> data)
{
var props = TypeDescriptor.GetProperties(typeof(T));
var table = new DataTable();
for (var i = 0; i < props.Count; i++)
{
var prop = props[i];
Type propertyType;
if (prop.PropertyType.IsGenericType &&
prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = prop.PropertyType.GetGenericArguments()[0];
}
else
{
propertyType = prop.PropertyType;
}
table.Columns.Add(prop.Name, propertyType);
}
var values = new object[props.Count];
foreach (var item in data)
{
for (var i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
Edited
What about this method?
public static DataTable ToDataTable(IList<AssociationModel> data)
{
var props = TypeDescriptor.GetProperties(typeof(AssociationModel));
var table = new DataTable();
for (var i = 0; i < props.Count; i++)
{
var prop = props[i];
Type propertyType;
if (prop.PropertyType.IsGenericType &&
prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = prop.PropertyType.GetGenericArguments()[0];
}
else
{
propertyType = prop.PropertyType;
}
table.Columns.Add(prop.Name, propertyType);
}
var values = new object[props.Count];
foreach (var item in data)
{
for (var i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
and your code will change like follow
if (SerialNumber != null)
{
ItemDetail = response.ItemDetail;
Parent = response.Parent;
DataTable dataTable = ToDataTable(response.Children.ToList());
}

Unable to get values of Object in Json array

I am facing problem with reading object values into Json array. please help me what is the problem here. Below is my code. I am sending employee list to get Json array. but i am not getting 'EmployeeDetails' in json array(that is in second level).
what is the problem here?
below is my code
class Program
{
static void Main(string[] args)
{
List<Employee> list = new List<Employee>();
Employee emp = new Employee { ID = 101, Department = "Stocks", EmployeeDetails = new Name { FirstName = "S", LastName = "Charles", Email = "abc#gmail.com" } };
Employee emp1 = new Employee { ID = 102, Department = "Stores", EmployeeDetails = new Name { FirstName = "L", LastName = "Dennis", Email = "Den#gmail.com" } };
list.Add(emp);
list.Add(emp1);
var resul1t = Program.GetEmployeeDetails(list);
}
private static string GetEmployeeDetails(List<Employee> emp)
{
string jsonarray = "";
if ((emp != null) && (emp.Count > 0))
{
Dictionary<string, object> dic = new Dictionary<string, object>();
int i = 0;
foreach (var awo in emp)
{
dic.Add(i.ToString(), ObjectToString(awo));
i++;
}
if (dic.Count > 0)
{
jsonarray = DictionnaryToArray(dic);
}
}
return jsonarray;
}
private static string ObjectToString(object obj)
{
Type objType = obj.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(objType.GetProperties());
StringBuilder sb = new StringBuilder(1024);
foreach (PropertyInfo prop in props)
{
var type = prop.GetValue(obj, null);
string attributeValueString = string.Format("\"{0}\":\"{1}\"", prop.Name, prop.GetValue(obj, null));
if (type != null && type.GetType() == typeof(double))
{
var doubleToStringValue = Convert.ToString(prop.GetValue(obj, null), System.Globalization.CultureInfo.InvariantCulture);
attributeValueString = string.Format("\"{0}\":\"{1:0.0}\"", prop.Name, doubleToStringValue);
}
sb.Append(attributeValueString).Append(";");
}
return "{" + sb.ToString().TrimEnd(new char[] { ';' }) + "}";
}
private static string DictionnaryToArray(Dictionary<string, object> data)
{
return "{" + string.Join(";", (from c in data select string.Format("\"{0}\":{1}", c.Key.ToString(), c.Value.ToString())).ToArray()) + "}";
}
}
public class Employee
{
public int? ID { get; set; }
public string Department { get; set; }
public Name EmployeeDetails { get; set; }
}
public class Name
{
public string LastName { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
}
Thanks
You could call ObjectToString recursively when you have a nested class, i'm changing little the ObjectToString, like the following code:
private static string ObjectToString(object obj)
{
Type objType = obj.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(objType.GetProperties());
StringBuilder sb = new StringBuilder(1024);
foreach (PropertyInfo prop in props)
{
string attributeValueString;
var type = prop.GetValue(obj, null);
if (type != null && type.GetType() == typeof(double))
{
var doubleToStringValue = Convert.ToString(prop.GetValue(obj, null), System.Globalization.CultureInfo.InvariantCulture);
attributeValueString = string.Format("\"{0}\":\"{1:0.0}\"", prop.Name, doubleToStringValue);
}//new code
else if (prop.PropertyType.IsNested)
{
attributeValueString = string.Format("\"{0}\":{1}", prop.Name, ObjectToString(type));
}
else
{
attributeValueString = string.Format("\"{0}\":\"{1}\"", prop.Name, type);
}
sb.Append(attributeValueString).Append(",");
}//updated code ; by ,
return "{" + sb.ToString().TrimEnd(new char[] { ',' }) + "}";
}
Note that, you need to replace ; by , to get a valid json.
Result
{
"0":{
"ID":"101",
"Department":"Stocks",
"EmployeeDetails":{
"LastName":"Charles",
"Email":"abc#gmail.com",
"FirstName":"S"
}
},
"1":{
"ID":"102",
"Department":"Stores",
"EmployeeDetails":{
"LastName":"Dennis",
"Email":"Den#gmail.com",
"FirstName":"L"
}
}
}
I hope this helps you fix the issue.

Nested List — Get list item of parent list

i want to write a C# function which returns "alamaba" when i pass "Montgomery".
2nd example: Sitka --> Alaska
here is the list of the example:
List<PopulationUSA> result = new List<PopulationUSA>();
PopulationUSA usa = new PopulationUSA("Population in USA", 316128839, new List<PopulationUSA>());
result.Add(usa);
PopulationUSA alabama = new PopulationUSA("Alabama", 4833722, new List<PopulationUSA>());
usa.Items.Add(alabama);
alabama.Items.Add(new PopulationUSA("Birmingham", 212113, null));
alabama.Items.Add(new PopulationUSA("Montgomery", 201332, null));
alabama.Items.Add(new PopulationUSA("Mobile", 194899, null));
PopulationUSA alaska = new PopulationUSA("Alaska", 735132, new List<PopulationUSA>());
usa.Items.Add(alaska);
alaska.Items.Add(new PopulationUSA("Juneau", 32660, null));
alaska.Items.Add(new PopulationUSA("Ketchikan", 8214, null));
alaska.Items.Add(new PopulationUSA("Sitka", 9020, null));
here is the class:
public class PopulationUSA
{
public PopulationUSA(string name, int value, List<PopulationUSA> items)
{
Name = name;
Value = value;
Items = items;
}
public string Name { get; set; }
public int Value { get; set; }
public List<PopulationUSA> Items { get; set; }
}
How can i do that?
Thanks
you can add this method to the PopulationUSA class
public string FindParentsOfGrandChildren(string _name)
{
List<PopulationUSA> parents = Items.Where(s => s.Items.Any(c => c.Name == _name)).ToList();
if (parents != null)
{
string listparents = string.Empty;
for (int i = 0; i < parents.Count; i++)
{
if (i == 0)
{
listparents += parents[i].Name;
}
else
{
listparents += ", " + parents[i].Name;
}
}
return listparents;
}
else
{
return "Not found";
}
}
then use it like this in your example:
string WhereDoIBelong = usa.FindParentsOfGrandChildren("Montgomery")
it would be much better as a recursive method, finding parents of any type (not just "grandchildren") but that is your work!

Map list to existing list in Automapper using a key

Automapper easily handles mapping one list of object types to another list of different objects types, but is it possible to have it map to an existing list using an ID as a key?
I have not found better way than the following.
Here are source and destination.
public class Source
{
public int Id { get; set; }
public string Foo { get; set; }
}
public class Destination
{
public int Id { get; set; }
public string Foo { get; set; }
}
Define converter (You should change List<> to whatever type you are using).
public class CollectionConverter: ITypeConverter<List<Source>, List<Destination>>
{
public List<Destination> Convert(ResolutionContext context)
{
var destinationCollection = (List<Destination>)context.DestinationValue;
if(destinationCollection == null)
destinationCollection = new List<Destination>();
var sourceCollection = (List<Source>)context.SourceValue;
foreach(var source in sourceCollection)
{
Destination matchedDestination = null;
foreach(var destination in destinationCollection)
{
if(destination.Id == source.Id)
{
Mapper.Map(source, destination);
matchedDestination = destination;
break;
}
}
if(matchedDestination == null)
destinationCollection.Add(Mapper.Map<Destination>(source));
}
return destinationCollection;
}
}
And here is actual mapping configuration and example.
Mapper.CreateMap<Source,Destination>();
Mapper.CreateMap<List<Source>,List<Destination>>().ConvertUsing(new CollectionConverter());
var sourceCollection = new List<Source>
{
new Source{ Id = 1, Foo = "Match"},
new Source{ Id = 2, Foo = "DoesNotMatchWithDestination"}
};
var destinationCollection = new List<Destination>
{
new Destination{ Id = 1, Foo = "Match"},
new Destination{ Id = 3, Foo = "DoeNotMatchWithSource"}
};
var mergedCollection = Mapper.Map(sourceCollection, destinationCollection);
You should get the following result.
I found this article very useful and as such I thought I would feed back in my generic version of the type converter which you can use to select the property to match on from each object.
Using it all you need to do is:
// Example of usage
Mapper.CreateMap<UserModel, User>();
var converter = CollectionConverterWithIdentityMatching<UserModel, User>.Instance(model => model.Id, user => user.Id);
Mapper.CreateMap<List<UserModel>, List<User>>().ConvertUsing(converter);
//The actual converter
public class CollectionConverterWithIdentityMatching<TSource, TDestination> :
ITypeConverter<List<TSource>, List<TDestination>> where TDestination : class
{
private readonly Func<TSource, object> sourcePrimaryKeyExpression;
private readonly Func<TDestination, object> destinationPrimaryKeyExpression;
private CollectionConverterWithIdentityMatching(Expression<Func<TSource, object>> sourcePrimaryKey, Expression<Func<TDestination, object>> destinationPrimaryKey)
{
this.sourcePrimaryKeyExpression = sourcePrimaryKey.Compile();
this.destinationPrimaryKeyExpression = destinationPrimaryKey.Compile();
}
public static CollectionConverterWithIdentityMatching<TSource, TDestination>
Instance(Expression<Func<TSource, object>> sourcePrimaryKey, Expression<Func<TDestination, object>> destinationPrimaryKey)
{
return new CollectionConverterWithIdentityMatching<TSource, TDestination>(
sourcePrimaryKey, destinationPrimaryKey);
}
public List<TDestination> Convert(ResolutionContext context)
{
var destinationCollection = (List<TDestination>)context.DestinationValue ?? new List<TDestination>();
var sourceCollection = (List<TSource>)context.SourceValue;
foreach (var source in sourceCollection)
{
TDestination matchedDestination = default(TDestination);
foreach (var destination in destinationCollection)
{
var sourcePrimaryKey = GetPrimaryKey(source, this.sourcePrimaryKeyExpression);
var destinationPrimaryKey = GetPrimaryKey(destination, this.destinationPrimaryKeyExpression);
if (string.Equals(sourcePrimaryKey, destinationPrimaryKey, StringComparison.OrdinalIgnoreCase))
{
Mapper.Map(source, destination);
matchedDestination = destination;
break;
}
}
if (matchedDestination == null)
{
destinationCollection.Add(Mapper.Map<TDestination>(source));
}
}
return destinationCollection;
}
private string GetPrimaryKey<TObject>(object entity, Func<TObject, object> expression)
{
var tempId = expression.Invoke((TObject)entity);
var id = System.Convert.ToString(tempId);
return id;
}
}

Categories

Resources