Selecting property values from IEnumerable<t> using an expression list? - c#

So I want to create a MVC helper where users can pass in a collection of expressions and the collection to pull those values from. This will create a table with the column Names and then a list of the values for those columns.
public class ColumnDefinition<T> where T: class
{
public Expression<Func<T,object>> Property { get; set; }
public string DisplayName { get; set; }
public string DefaultValue { get; set; }
public bool IsVisisble { get; set; }
public string CssClass { get; set; }
}
So the helper might look like this:
public static IHtmlString ToTable<T>(this HtmlHelper helper, IEnumerable<T> list, IEnumberable<ColumnDefinition<T>> columnDefs) where T: class
{
....
}
I know how to get the Property name fromthe Expression<Func<T,object>>, but not sure how to wrtiethe select statement for the list. this should work to get the values:
var someList= list.Select(() => columnDefs.Select(c => c.Property)).ToList();
I am trying to figure out how to Line up the Name with the value. So an exmaple might be this:
var colDef = new List<ColumnDefinition<Foo>>()
{
new ColumnDefinition<Foo>()
{
Property = f => f.Id,
DisplayName = "Foo"
},
new ColumnDefinition<Foo>()
{
Property = f => f.Bar.Name,
}
}
So when that set of column definitions gets passed into the helper, I'd like to Get all the property names unless the DisplayName is present (i understand how to get the names) then I want to write the data for each one of those column definitions.
Update
So I have this so far:
public static class DataTablesHelper
{
public static DataTableModel GnerateColumns<T>(IEnumerable<T> list,
IEnumerable<ColumnDefinition<T>> columnDefinitions) where T: class
{
foreach (var o in list)
{
var newList = GetInfo(o, columnDefinitions.ToList());
}
return new DataTableModel();
}
private static List<string> GetInfo<T>(T source, IEnumerable<ColumnDefinition<T>> columnDefinitions) where T : class
{
return columnDefinitions.Select(columnDefinition => columnDefinition.Property(source).ToString()).ToList();
}
}
public class ColumnDefinition<T> where T: class
{
public Func<T,object> Property { get; set; }
public string DisplayName { get; set; }
public string Value { get; set; }
public string SortValue { get; set; }
public bool IsVisisble { get; set; }
public string CssClass { get; set; }
}
This seems to work on getting the values and I can grab the Property names later. Ideally, it would be nice to pass in a string formatter to format the output.
Update 2
So, using this technique which has been part of my core library now for some time, I came up with this to allow for simple formatting:
private static List<string> GetInfo<T>(T source, IEnumerable<ColumnDefinition<T>> columnDefinitions) where T : class
{
var listValues = new List<string>();
foreach (var columnDefinition in columnDefinitions.ToList())
{
var prop = columnDefinition.Property(source);
var definition = columnDefinition;
TypeSwitch.Do(prop, TypeSwitch.Case<DateTime>(p => listValues.Add(p.ToString(definition.Format))),
TypeSwitch.Default(() => listValues.Add(prop.ToString())));
}
return listValues;
}
I added a string that will house the formatter.
public class ColumnDefinition<T> where T: class
{
public Func<T,object> Property { get; set; }
public string Format { get; set; }
public string DisplayName { get; set; }
public string Value { get; set; }
public string SortValue { get; set; }
public bool IsVisisble { get; set; }
public string CssClass { get; set; }
}

Related

How to manually map a List of object to a list of DTO?

I have these:
public class FamilyHead
{
public Guid HeadId { get; set; }
public string Name { get; set; }
}
public class Citizen
{
public Guid Id { get; set; }
public string Name { get; set; }
public short Age { get; set; }
// more properties
[ForeignKey("FamilyHead")]
public Guid HeadId { get; set; }
public virtual FamilyHead FamilyHead { get; set; }
}
public class CitizenDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
public short Age { get; set; }
public Guid HeadId
public string HeadName { get; set; }
}
I can manually map it via extension method if it is a single instance:
public static CitizenDTO ToDTO(this Citizen citizen)
{
if (citizen == null) return null;
return new CitizenDTO {
Id = citizen.Id,
Name = citizen.Name,
HeadId = citizen.HeadId,
HeadName = citizen.FamilyHead.Name
}
}
var dto = aCitizen.ToDTO();
But how to map a list of citizens? I think Select() might do the work but I only know how to do it if the model and the dto have a same structure. Like this example:
IEnumerable<int> integers = new List<int>() { 1, 2, 3, 4, 5 };
IEnumerable<string> strings = integers.Select(i => i.ToString());
So how to map a list of it?
You can use Linq Select() as you used for string in your question, no need to write long extension method
IEnumerable<CitizenDTO> dto = citizens.Select(x => x.ToDTO());
I found the answer before finishing my question. Just iterate through the list and add mapped DTO to it. Silly me
// Extension method
public static IEnumerable<CitizenDTO> ToDTO(this IEnumerable<Citizen> citizens)
{
if (citizen == null) return null;
var dto = new List<CitizenDTO>();
foreach(var citizen in citizens) {
dto.Add(citizen.ToDTO());
}
return dto;
}
// How to use
IEnumerable<CitizenDTO> result = listOfCitizens.ToDTO();

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

How to go about combining two objects, manipulate the data, then separate them?

I have two classes with some similar fields, some different, and a form that utilizes two different objects depending on what mode it's in (insert/edit).
Instead of using two different objects and if statements checking the form mode, I'd like to have one struct to be hydrated with either of the two objects fields so I can manipulate one object through the page life-cycle. Then separated the struct back to its respective object for insert/updating the DB.
Example of classes:
public partial class SomeClass
{
public Int32 B {get;set;}
public String C {get;set;}
public Boolean D {get;set;}
}
public class SomeOtherClass
{
public Int32 A {get;set;}
public Int32 B {get;set;}
public String C {get;set;}
}
Update with Solution Example:
public interface IInsertable
{
string SharedName { get; set; }
string SharedID { get; set; }
string editedFieldValue { get; set; }
long GetSuperSecreteInfo();
}
internal class InsertableImplementation : IInsertable
{
public string SharedName { get; set; }
public string SharedID { get; set; }
public string editedFieldValue { get; set; }
public long GetSuperSecreteInfo()
{
return -1;
}
}
public interface IUpdateable
{
string SharedName { get; set; }
string SharedID { get; set; }
string updatedFieldValue { get; set; }
Guid GenerateStevesMagicGuid();
}
internal class UpdateableImplementation : IUpdateable
{
public string SharedName { get; set; }
public string SharedID { get; set; }
public string updatedFieldValue { get; set; }
public Guid GenerateStevesMagicGuid()
{
return new Guid();
}
}
public static class WonderTwinFactory
{
public static WonderTwins GenerateWonderTwin(IUpdateable updateable, IInsertable insertable)
{
var wt = new WonderTwins();
// who will win?
wt.SharedID = updateable.SharedID;
wt.SharedID = insertable.SharedID;
// you decide?
wt.SharedName = updateable.SharedName;
wt.editedFieldValue = "stuff";
return wt;
}
}
public class WonderTwins : IInsertable, IUpdateable
{
public string SharedName { get; set; }
public string SharedID { get; set; }
public string editedFieldValue { get; set; }
public long GetSuperSecreteInfo()
{
return 1;
}
public string updatedFieldValue { get; set; }
public Guid GenerateStevesMagicGuid()
{
return new Guid();
}
}
class Program
{
static void Main(string[] args)
{
IUpdateable updateable = new UpdateableImplementation();
IInsertable insertable = new InsertableImplementation();
WonderTwins dualImplementatin = WonderTwinFactory.GenerateWonderTwin(updateable, insertable);
IUpdateable newUpdateable = dualImplementatin as IUpdateable;
IInsertable newInsertable = dualImplementatin as IInsertable;
}
}
Have both classes implement an interface that defines the operations common to each, including both the fields that are shared (assuming the view needs to access them) and also a method to actually perform the operation that they represent (insert/edit).
Other way of doing such things is using C# dynamic object and assign properties directly. It may help to avoid any new type or interface and directly utilizing new dynamic object any time, as much as required.
var newObject = new {
objectOfClass1 = x.prop1,
objectOfClass2 = x.prop2
}

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();

How to convert DataSet to Entity in C#?

Here I came up with the first approach: that is, using foreach clause on DataSet to get the items and fill in your Entity. But this method can't be reused when the something changes.
So I think maybe reflection should be the best approach for my scenario. below are the details:
1.My entity is defined below:
using System.ComponentModel;
namespace WarningServiceForYM.Model
{
public class StuffEntity
{
[Description("企业ID")]
public string EnterpriseID { get; set; }
[Description("冰柜编号")]
public string FridgeID { get; set; }
[Description("冰柜名称")]
public string FridgeName { get; set; }
[Description("手机号码")]
public string PhoneNumber { get; set; }
[Description("设备名称")]
public string EquipmentName { get; set; }
[Description("采集参数")]
public string PickingParams { get; set; }
[Description("一路温度")]
public string TempOne { get; set; }
[Description("二路温度")]
public string TempTwo { get; set; }
[Description("三路温度")]
public string TempThree { get; set; }
[Description("四路温度")]
public string TempFour { get; set; }
[Description("五路温度")]
public string TempFive { get; set; }
[Description("六路温度")]
public string TempSix { get; set; }
[Description("七路温度")]
public string TempSeven { get; set; }
[Description("八路温度")]
public string TempEight { get; set; }
[Description("温度最低")]
public string Min { get; set; }
[Description("温度最高")]
public string Max { get; set; }
[Description("采集时间")]
public string PickingTime { get; set; }
[Description("通知间隔")]
public string WarningPeriod { get; set; }
[Description("延时")]
public string PendingTime { get; set; }
[Description("通知开关")]
public string Switch { get; set; }
[Description("最后通知时间")]
public string LastInformTime { get; set; }
}
}
Below is the DataSet screenshot:
I have saved this DataSet's data into csv file, pls click here to find it.
the inner properties in the StuffEntity have the same Description as the column headers in DataSet.
Would any one give me a method to show how to convert this Dataset to StuffEntity ? thx.
Ok, using reflection:
public static T GetEntity<T>(DataRow row) where T : new()
{
var entity = new T();
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
//Get the description attribute
var descriptionAttribute = (DescriptionAttribute)property.GetCustomAttributes(typeof(DescriptionAttribute), true).SingleOrDefault();
if (descriptionAttribute == null)
continue;
property.SetValue(entity, row[descriptionAttribute.Description]);
}
return entity;
}
You can use it like:
foreach (DataRow dataRow in dataSet.Tables[0].Rows)
{
var e = GetEntity<StuffEntity>(dataRow);
Console.WriteLine(e.EnterpriseID);
}
It's a generic implementation, so you can use it with any other types or datasets you want.
I took care to made it as simple as possible, so it can be widely improved adding some consistences, like checking if the column name exists before setting the entity value or verifying duplicate descriptions as needed. It can also be converted to an extension method for the DataRow, DataTable or DataSet, for example.
I my case Your code almost worked, but
descriptionAttribute is always null so it continues to the point where I get no results back
var descriptionAttribute = (DescriptionAttribute)property.GetCustomAttributes(typeof(DescriptionAttribute), true).SingleOrDefault();
if (descriptionAttribute == null)
continue;
I am not sure what is happening to the variable descriptionAttribute and it is null all the time.
So I changed #natenho code like this and it worked for me.
public static T GetEntity<T>(DataRow row) where T : new()
{
var entity = new T();
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
//Get the description attribute
//var descriptionAttribute = (DescriptionAttribute)property.GetCustomAttributes(typeof(DescriptionAttribute), true).SingleOrDefault();
//if (descriptionAttribute == null)
// continue;
if (row[property.Name].ToString() != "")
{
property.SetValue(entity, row[property.Name]);
}
}
return entity;
}

Categories