c# - Use linq to map parent child structure -
i have domain classes separated ones use in views, when retrieving data have map domain classes view ones. until have been straight forward, have case in need map parent-child classes domain parent-child classes on view.
using foreach
structures works fine, have quite few linq methods mapping between domain , view classes, need refactored accomodated new requirements , faster if knew how linq. in advance.
as example of i'm trying accomplish see code below:
in repository have classes:
public class parent { public int parentid { get; set; } public string parentname { get; set; } }; public class childa : parent { public string childpropertya { get; set; } }; public class childb : parent { public string childpropertyb { get; set; } };
then in ui have classes:
public class parentvm { public int parentidvm { get; set; } public string parentnamevm { get; set; } }; public class childavm : parentvm { public string childpropertyavm { get; set; } }; public class childbvm : parentvm { public string childpropertybvm { get; set; } };
now have service class in methods 1 below:
public getparentvms() { var parents = initializerepositoryclass(); var parentsvm = maprepositorytoviewclasses(parents); showresult(parentsvm); }
where:
public list<parent> initializerepositoryclass() { var parents = new list<parent>(){ new childa(){parentid=1, parentname="parent 1", childpropertya="a"}, new parent(){parentid=2, parentname="parent 2"}, new childb(){parentid=3, parentname="parent 3", childpropertyb="b"}, }; return parents; } private list<parentvm> maprepositorytoviewclasses(list<parent> parents) { var parentsvm = new list<parentvm>(); foreach (var item in parents) { if (item childa) { var itemvm = item childa; parentsvm.add( new childavm() { parentidvm = itemvm.parentid, parentnamevm = itemvm.parentname, childpropertyavm = itemvm.childpropertya } ); } else if (item childb) { var itemvm = item childb; parentsvm.add( new childbvm() { parentidvm = itemvm.parentid, parentnamevm = itemvm.parentname, childpropertybvm = itemvm.childpropertyb } ); } else { var itemvm = item parent; parentsvm.add( new parentvm() { parentidvm = itemvm.parentid, parentnamevm = itemvm.parentname } ); } } return parentsvm; } private void showresult(list<parentvm> parentsvm) { foreach (var item in parentsvm) { if (item childavm) { var ca = (childavm)item; console.writeline("child " + ca.childpropertyavm); } else if (item childbvm) { var cb = (childbvm)item; console.writeline("child b " + cb.childpropertybvm); } else { console.writeline("parent "); } } }
the code above work, change method maprepositorytoviewclasses uses linq, , looks 1 below:
private list<parentvm> maprepositorytoviewclasseslinq(list<parent> parents) { var parentsvm = p in parents case p childa select new childavm() {childpropertyavm = p.childpropertya, ...}; else p childb select new childbvm() {childpropertybvm = p.childpropertyb, ...}; else select new parentvm() {parentidvm = p.parentid}; return parentsvm.tolist(); }
any ideas? thanks.
you need changes in code make better
1) have introduce factory create vm's instances.
class vmfactory { public parentvm create(parent obj) { var childa = obj childa; if (childa != null) { return new childavm() { parentidvm = childa.parentid, parentnamevm = childa.parentname, childpropertyavm = childa .childpropertya }; } var childb = obj childb; if(childb != null) { return new childbvm() { parentidvm = childb.parentid, parentnamevm = childb.parentname, childpropertybvm = childb.childpropertyb }; } return new parentvm() { parentidvm = obj.parentid, parentnamevm = obj.parentname }; } }
2) can simplify code @ maprepositorytoviewclasses method
private list<parentvm> maprepositorytoviewclasses(list<parent> parents) { // factory instance can provided outer scope var factory = new vmfactory(); var parentsvm = new list<parentvm>(); foreach (var item in parents) { parentsvm.add(factory.create(item)); } return parentsvm; }
3) final step, let's use linq map
private list<parentvm> maprepositorytoviewclasses(list<parent> parents) { // factory instance can provided outer scope var factory = new vmfactory(); return parents.select(factory.create).tolist(); }
it's done
yet attempt solve it
1) create extensions solve common tasks.
static class ext { public static parentvm map<tin>(this tin obj, func<tin, parentvm> func) tin : parent { var source = obj tin; return source != null ? func(obj) : null; } }
2) use extension method vms
private list<parentvm> maprepositorytoviewclasseslinq(list<parent> parents) { var tmp = p in parents select p.map<childa>(c => new childavm() { parentidvm = c.parentid, parentnamevm = c.parentname, childpropertyavm = c.childpropertya }) ?? p.map<childb>(c => new childbvm() { parentidvm = c.parentid, parentnamevm = c.parentname, childpropertybvm = c.childpropertyb }) ?? new parentvm() { parentidvm = obj.parentid, parentnamevm = obj.parentname }; return tmp.tolist(); }
Comments
Post a Comment