Loop through objects properties in an object - c#

I have got an object like below
public class MainObj
{
public int BankDetailPercentage { get; set; }
public int PersonalDetailPercentage { get; set; }
public BankDetail BankDetail { get; set; }
public PersonalDetail PersonalDetail { get; set; }
}
public class BankDetail
{
public string Name { get; set; }
public string Branch { get; set; }
public string AccountNumber { get; set; }
}
public class PersonalDetail
{
public string Name { get; set; }
public string address { get; set; }
}
I need to loop through that MainObj Object and find how many properties of BankDetail and PersonalDetail objects are filled and on the basis of that I should set the percentage of filled properties in MainObj object's BankDetailPercentage and PersonalDetailPercentage fields and return it. How can I accomplish this, I have tried below but couldn't get how to do it
public MainObject calculatePercentage(MainObject mainObject)
{
int bdCount = 0, pdCount = 0, bdTotal = 3, pdTotal = 2;
PropertyInfo[] properties = typeof(MainObject).GetProperties();
foreach (var property in properties)
{
var value = property.GetValue(mainObject);
if (property.Name == "BankDetail")
{
//
}
}
return mainObject;
}

First you will need to get the instance of the object in question (which you have done in your code above.
var value = property.GetValue(mainObject);
Then you need to count how many properties are contained in that object. To do that we need to first get the properties.
var subProperties = property.PropertyType.GetProperties();
var propertyCount = subProperties.Length;
Now we need to check each of those properties to see if a value is set.
var populatedCount = 0;
foreach (var subProperty in subProperties)
{
if (!string.IsNullOrEmpty(subProperty.GetValue(value)))
{
populatedCount++;
}
}
Then take the percentage.
var percentage = (float)populatedCount / propertyCount;

Related

What's the most efficient way of using AutoMapper to update / append to array?

I have an array of a class MyClassDTO that needs to be used to update items in the MyClass array:
public class MyClass
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
}
public class MyClassDTO
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
}
I was thinking using a dictionary to store the values from the DB and, then, iterate over the updated values and either update an existing value or create a new one. Something like this:
public void UpdateMyClassArray(IEnumerable<MyClassDTO> myClassDTOArray)
{
var currentValuesInDB = GetArray();
var myDictionary = new Dictionary<int, MyClass>();
foreach (var myClass in currentValuesInDB)
myDictionary.Add(myClass.Id, myClass);
var updatedMyClasses = myClassDTOArray
.Select(myClassDTO =>
{
if (myClassDTO.Id is null)
return Mapper.Map<MyClass>(myClassDTO);
int id = myClassDTO.Id.Value;
if (!myDictionary.ContainsKey(id))
return Mapper.Map<MyClass>(myClassDTO);
var storedMyClass = myDictionary[id];
return Mapper.Map(myClassDTO, storedMyClass);
});
SaveChanges(updatedMyClasses);
}
My question is: is there a better way of doing this? Does AutoMapper provide a built-in method for dealing with this case?

How to access property inside property?

I have a model class like this:
public class MapModel
{
public Field[] Fields { get; set; }
}
public class Field
{
public int Id { get; set; }
public string Name { get; set; }
public Node[] Nodes { get; set; }
public string Icon { get; set; }
}
public class Node
{
public float Long { get; set; }
public float Lat { get; set; }
}
In my view model I'm calling a service to get some map data and ObservableCollection like:
public ObservableCollection<Field> FieldsCollection { get; set; } = new ObservableCollection<Field>();
var mapData = await MapService.GetMapData(token, "sr");
foreach (var md in mapData.Fields)
{
FieldsCollection.Add(md);
PinIcon = Icon;
}
Now I'm trying to set values Long and Lat from Node for position of Pin on map...
public void LoadMapTab()
{
foreach (var item in FieldsCollection)
{
var pin = new Pin
{
Label = item.Name,
Position = new Position(/* SET VALUES FROM NODE LONG AND LAT*/),
Icon = BitmapDescriptorFactory.FromBundle(PinIcon)
};
_map.Pins.Add(pin);
Device.StartTimer(TimeSpan.FromMilliseconds(500), () =>
{
_map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(/* SET VALUES FROM NODE LONG AND LAT*/),
Distance.FromKilometers(8)));
return false;
});
}
}
So, my question is how to access the Long and Lat values and set them in
Position = new Position(.......)
item is a Field, so it has a Nodes array. You can use an indexer [] to specify an index in the array
Position = new Position(item.Nodes[0].Lat, item.Nodes[0].Long),
note, attribtute has a specific meaning in C#. These are properties, not attributes

How to compare object and List<> and object.value null when the value doesn't exist in list

I need to compare between my object and a list.
List contains attribute "nom_colonne", it fill by a query and the result is a list of attributes (same like my object AppareilsReparations)
For example :
if droit_utilisateur.nom_colonne = "Num_dossier"
so i keep the value in arp.num_dossier
But if i don't have this value of my list droit_utilisateur :
arp.num_dossier will be null.
I wanted to cast my object with System.Collections.IList but impossible to cast. I have an error.
public class AppareilsReparations
{
public string Num_dossier { get; set; }
//public string reference_aff { get; set; }
public int Id { get; set; }
public Guid Uid { get; set; }
public string ref_sav { get; set; }
public CodeDefaut codedefaut { get; set; }
public CodeSymptome codesymptome { get; set; }
}
public class Droits
{
public int id { get; set; }
public int utilisateur_id { get; set; }
public string nom_table { get; set; }
public string nom_colonne { get; set; }
}
AppareilsReparations arp = db.Query<AppareilsReparations>
("select * from v_appareils_reparations where ref_sav_client =#ref_sav", new { ref_sav }).SingleOrDefault();
List<Droits> droit_utilisateur = GetDroits("admin");
//var appareil = new List<AppareilsReparations>();
IList appareil = (IList)arp;
var result = droit_utilisateur.Where(x => !appareil.Contains(x.nom_colonne)).ToList();
That's cause AppareilsReparations is not a type of IList and thus your cast would always fail IList appareil = (IList)arp;. Probably you wanted to do like below; just comparing with Num_dossier field of AppareilsReparations type
var result = droit_utilisateur.Where(x => x.nom_colonne == arp.Num_dossier).ToList();
i have found my problem, i post my code for everybody :
List<Droits> droit_utilisateur = GetDroits(username);
Type myType = e.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo prop in e.GetType().GetProperties())
{
object propValue = prop.Name;
if (droit_utilisateur.Any(s => s.nom_colonne.Contains(prop.Name/*, StringComparison.OrdinalIgnoreCase)*/) == false))
{
prop.SetValue(e, Convert.ChangeType(null, prop.PropertyType), null);
}
}
return e;

Match names in list with elements in class

I wonder if there's any way to match the names in a list with the elements in a class:
I have a class:
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
and a List: List<exampleClass> EnfSist
So that's the way the list is made. Now I would like to know how to match or identify the string inside "name" from my list. To match this class:
tbl_sistematicas b = new tbl_sistematicas
{
ap_enf_id_enfermedad = Convert.ToInt32(EnfSist[0].value),
ap_pac_inicio = Convert.ToInt32(EnfSist[1].value),
ap_pac_inicio_periodo = Convert.ToInt32(2].value),
ap_pac_duracion = Convert.ToInt32(EnfSist[3].value),
ap_pac_duracion_periodo = Convert.ToInt32(EnfSist[4].value),
ap_pac_tratamiento = EnfSist[5].value
};
Once being able to match the same names I won't have to specify each index of every element in the list. The elements in the list have the same name as in the table. Not all elements of the class are being used.
I have something like this: tbl_sistematicas bh = EnfSist.FindAll(x => x.name == bh.?????? );
If I understand the question, you can do this using something like automapper or ValueInjector
An example using ValueInjector
void Main()
{
List<exampleClass> EnfSist = new List<exampleClass>();
EnfSist.Add(new exampleClass { name = "ap_enf_id_enfermedad", value = "12" });
EnfSist.Add(new exampleClass { name = "apap_pac_inicio" , value = "34" });
// etc
tbl_sistematicas b = new tbl_sistematicas();
b.InjectFrom<MyInjection>(EnfSist);
}
public class MyInjection : KnownSourceValueInjection<List<exampleClass>>
{
protected override void Inject(List<exampleClass> source, object target)
{
foreach(var entry in source)
{
var property = target.GetProps().GetByName(entry.name, true);
if (property != null)
property.SetValue(target, Convert.ChangeType(entry.value, property.PropertyType));
}
}
}
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
public class tbl_sistematicas
{
public int ap_enf_id_enfermedad { get; set; }
public int apap_pac_inicio { get; set; }
public int ap_pac_inicio_periodo { get; set; }
public int ap_pac_duracion { get; set; }
public int ap_pac_duracion_periodo { get; set; }
public string ap_pac_tratamiento { get; set; }
}
Note, this will throw an exception if the value can not be converted to an int

Only return specific properties

I have developed my first API controlled in MVC4 and through the scaffolding I have got it to automatically output a list of items:
// GET api/ItemList
public IEnumerable<ItemOption> GetItemOptions()
{
var itemoptions = db.ItemOptions.Include(i => i.Item);
return itemoptions.AsEnumerable();
}
This shows all the item properties from my model:
public class ItemOption
{
public int ItemOptionId { get; set; }
public bool Active { get; set; }
public string Name { get; set; }
public string test1 { get; set; }
public double PriceNet { get; set; }
}
How can I specify specific fields I wish to be returned? For example, I just want the ItemOptionId, Active and Name to be returned.
I have tried adding additional includes, but this seems to be at an object level.
Try creating a new type to represent the properties you'd like to return:
public class ItemOptionResult
{
public int ItemOptionId { get; set; }
public bool Active { get; set; }
public string Name { get; set; }
}
And then projecting your ItemOption collection, like this:
// GET api/ItemList
public IEnumerable<ItemOptionResult> GetItemOptions()
{`enter code here`
var itemoptions =
db.ItemOptions
.Select(i =>
new ItemOptionResult
{
ItemOptionId = i.ItemOptionId,
Active = i.Active,
Name = i.Name
});
return itemoptions.AsEnumerable();
}
Try this :
var itemoptions = db.ItemOptions.Select(io => new ItemOption()
{
ItemOptionId = io.ItemOptionId,
Active = io.Active ,
Name = io.Name
}
return itemoptions.AsEnumerable();

Categories