I have a set of nested classes from datasource (VSO) and I would like to mapped to contracts. The point of mapping is the next:
the mapped object (contract) will have a new property, called AreaPathFull, which will have the concatenated AreaPath values of all nodes above it in the tree.
Why I want this?:
it is for displaying purposes on UI
it can be solved on UI side by dealing with javascript is pain in the bottom for me, C# much easier, might not be the best idea ever, but still...
Question:
it is possible to achieve this by using Automapper?
Unfortunately, I have almost nothing experience with Automapper and if it is not possible then I would not like to spend my time with it. If so, then I think, CustomValueResolve will be my friend.
Source:
public class Class1ToBeMapped
{
public string AreaPath = "Level1";
public List<Class1ToBeMapped> Children = new List<Class1ToBeMapped>()
{
{new Class1ToBeMapped()
{
AreaPath = "Level21",
Children = new List<Class1ToBeMapped>(){}
}},
{new Class1ToBeMapped()
{
AreaPath = "Level22",
Children = new List<Class1ToBeMapped>(){}
}}
};
}
Mapped object, desired result:
public class Class2Mapped
{
public string AreaPath = "Level1";
public string AreaPathFull = "Level1";
public List<Class2Mapped> Children = new List<Class2Mapped>()
{
{
new Class2Mapped()
{
AreaPath = "Level21",
AreaPathFull = "Level1/Level21",
Children = new List<Class2Mapped>()
{
{
new Class2Mapped()
{
AreaPath = "Level31",
AreaPathFull = "Level1/Level21/Level31",
Children = new List<Class2Mapped>()
{
{
new Class2Mapped()
{
AreaPath = "Level41",
AreaPathFull = "Level1/Level21/Level31/Level41",
Children = null
}
}
}
}
},
{
new Class2Mapped()
{
AreaPath = "Level22",
AreaPathFull = "Level1/Level22",
Children = new List<Class2Mapped>()
{
new Class2Mapped()
{
AreaPath = "Level32",
AreaPathFull = "Level1/Level22/Level32",
Children = null
}
}
}
}
}
},
}
};
}
Related
I'm trying to make a hierarchical item source from a datatable whose fields are(Unique_id,Lookup_Value,Parent_Id,Is_Parent,Category_Level) where each record either be a parent or child. I'm trying with recursion but multilevel cannot be achieved. How can it be?
1.first i have filtered all parent nodes where is_parent=true;
2.i have passed each root to a recursive method for finding its child.
i have achieved two level.
private void CreateHierarchicalScanningCategory(DataTable scanningcategory)
{
Task<List<ScanningMenuItem>> scaningmenuitem =
Task.Factory.StartNew(() => CreateHierarchicalTemplate(scanningcategory));
}
private List<ScanningMenuItem> CreateHierarchicalTemplate(DataTable scanningcategory)
{
Func<DataRow, ScanningMenuItem, ScanningMenuItem> _funcfor_parentchild = null;
_funcfor_parentchild = (parentrow, menuitem) =>
{
var childrows = this._scanning_Category.AsEnumerable().Where
(row => Convert.ToInt32(row["Parent_Id"]) == Convert.ToInt32(parentrow["Gen_Lookup_Id"]));
if (childrows != null && childrows.Any())
{
foreach (var item in childrows)
{
var foo = new ScanningMenuItem { Title = Convert.ToString(item["Lookup_Value"]) };
menuitem.Items.Add(foo);
_funcfor_parentchild(item, menuitem);
}
}
return menuitem;
};
var parentnodes = scanningcategory.Copy().AsEnumerable().Where(row => Convert.ToBoolean(row["Is_Parent"]) == true);
if (parentnodes.Any())
{
List<ScanningMenuItem> menuitem = new List<ScanningMenuItem>();
foreach (var item in parentnodes)
{
ScanningMenuItem root = new ScanningMenuItem { Title = Convert.ToString(item["Lookup_Value"]) };
var node_menuitem = _funcfor_parentchild(item, root);
menuitem.Add(node_menuitem);
}
return menuitem;
}
return null;
}
ScanningMenuItem:
public class ScanningMenuItem
{
public ScanningMenuItem()
{
this.Items = new ObservableCollection<ScanningMenuItem>();
}
public string Title { get; set; }
public ObservableCollection<ScanningMenuItem> Items { get; set; }
}
Datatable structure:
DataTable dt = new DataTable
{
Columns = { { "Unique_id", typeof(int) },
{"Lookup_Value" }, {"Parent_Id",typeof(int) },
{ "Is_Parent",typeof(int) }, {"Category_Level",typeof(int) } }
};
dt.Rows.Add(150, "EMR",0,1,1);
dt.Rows.Add(100361, "Cardiology",150,0,2);
dt.Rows.Add(100362, "Gastrology",150,0,2);
dt.Rows.Add(152, "Discharge Summary",0,1,1);
dt.Rows.Add(1385,"Investigations/Procedures", 0, 1, 1);
dt.Rows.Add(1700, "DENTAL",0,1,1);
dt.Rows.Add(633671, "EMR2",0, 1,1);
dt.Rows.Add(151, "FO",0, 1,1);
dt.Rows.Add(117370,"External Sick Leave",151, 0, 2);
dt.Rows.Add(117371,"External Appointment",151, 0, 2);
dt.Rows.Add(117372,"Heart Transplantation",100361, 0, 3);
The Datatable is dynamic. don't know how many levels are coming.
1.EMR
1.1 Cardiology
1.1.1 Heart Transplantation
1.2 Gastrology
2.FO
2.1 External Appointment
2.2 External Appointment
3.EMR2
3.1 Discharge
3.2 DENTAL
3.3 Investigations/Procedures"`enter code here`
Hi I have the following code when I am adding values to a list.
var NoLiftingList = new List<SQLFields>();
SQLFields nolifting = new SQLFields();
nolifting.Field1 = "No lifting";
NoLiftingList.Add(nolifting);
SQLFields extremelifting = new SQLFields();
extremelifting.Field1 = "Up to 100 lbs (extreme lifting)";
NoLiftingList.Add(extremelifting);
How can I simplify this? Instead of initializing a new object all the time.
This is the code for the whole class updated below.
Thanks
You can add to a list, and set properties on a class by using this inline constructor syntax (working example):
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var NoLiftingList = new List<SQLFields>
{
new SQLFields
{
Field1 = "No Lifting"
},
new SQLFields
{
Field1 = "Up to 100lbs (extreme lifting)"
}
};
}
}
public class SQLFields
{
public string Field1 { get; set; }
}
Use Object Initializers with anonymous types
var NoLiftingList = new List<SQLFields>(){
new SQLFields() { Field1 = "No lifting"},
new SQLFields() { Field1 = "Up to 100 lbs (extreme lifting)"}
};
Ref: MSDN Link
Try this
var NoLiftingList = new List<SQLFields>()
{
new SQLFields()
{
Field1 = "No lifting"
},
new SQLFields()
{
Field1 = "Up to 100 lbs (extreme lifting)"
}
};
I am trying to bulk insert using EF (model first) on two tables that have a FK relationship (one to many). The code below properly inserts all of the Challenge entries but only inserts the X amount Shortages one time. My expectation... I have 10 shortages with 2 challenges. I should receive 2 challenge entries and 20 shortage entries. I am only seeing 10 challenge entries for the first shortage inserted. (the code below is simplified)
//class for cloning Shortage collection
public class ShortageCollection : Collection<Shortage>
{
public ShortageCollection(IList<Shortage> source) : base(source) { }
public ShortageCollection() { }
public ShortageCollection Clone()
{
return Clone(this);
}
public static ShortageCollection Clone(ShortageCollection shortage)
{
var res = new ShortageCollection();
foreach (var s in shortage)
{
res.Add(s.Clone());
}
}
}
public class Shortage : StandardDB.Shortage
{
public Shortage Clone()
{
return new Shortage()
{
PART_NUMBER = this.PART_NUMBER,
Note = this.Note,
Qty = this.Qty,
ResponseMachine = this.ResponseMachine
};
}
}
public void CreateChallenge()
{
var JSONJobs = new JavaScriptSerializer().Deserialize<string[]>(Jobs);
var JSONParts = new JavaScriptSerializer().Deserialize<ChallengePartsList[]>(Parts);
using (ARTEntities art = new ARTEntities())
{
art.Configuration.AutoDetectChangesEnabled = false;
art.Configuration.ValidateOnSaveEnabled = false;
ShortageCollection sColl = new ShortageCollection();
foreach(var part in JSONParts)
{
Shortage s = new Shortage()
{
PART_NUMBER = part.Invid,
Note = Challenge,
Qty = part.Qty,
ResponseMachine = ResponseMachine
};
sColl.Add(s);
}
foreach (var job in JSONJobs) {
Challenge c = new Challenge()
{
InitiatorORG = Org,
TypeID = TypeID,
DISCRETE_JOB = job,
InitiatorPERSON_ID = InitiatorPersonID,
InitiatedDate = datenow,
Challenge1 = Challenge,
ChampionGroupID = ChampionGroupID,
StatusID = StatusID,
InitiatorGroupID = InitiatorGroupID,
DivisionID = DivisionID,
Shortages = sColl.Clone()
};
art.Challenges.Add(c);
}
art.SaveChanges();
}
}
you are only creating 10 Shortages in memory. Your Clone method is a shallow clone, and doesn't go through and clone every object. Therefore you have 2 lists with 10 identical items (each pair of items point to exactly same memory reference).
What you need to do is DeepClone which is something like the following:
public static ShortageCollection Clone(ShortageCollection shortage)
{
var res = new ShortageCollection();
foreach(var s in shortage) {
res.Add( s.Clone() );
}
return res;
}
And in your shortage class:
public class Shortage
{
public Shortage Clone()
{
return new Shortage()
{
SomeProp = this.SomeProp,
SomeOtherProp = this.SomeOtherProp
}
}
}
Be aware that if inside shortage any of those objects point to another entity, each pair will point to the same entity.
Search for DeepClone for more info
I used to compare lists like this, but it returns false in a test:
Assert.IsTrue(expected.SequenceEquals(actual));
And tried converting to json and it worked:
Assert.AreEqual(expected.ToJson(), actual.ToJson());
Values seems to be equal, what could be different? How to find out what is different in the lists?
Updated:
My class:
public class Department
{
[BsonId]
public ObjectId Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Id.ToString();
}
}
If MyClass implements IEquatable<MyClass>, then try this:
expected.Sort();
actual.Sort();
if (Enumerable.SequenceEqual(actual, expected)) { ... }
If it does not implement IEquatable then you could expect strange behavior, since the object references will be compared in the two lists, and not their fields:
using System;
using System.Collections.Generic;
using System.Linq;
public class MyClassA
{
private int i;
public MyClassA(int i) { this.i = i; }
}
public class MyClassB : IEquatable<MyClassB>
{
private int i;
public MyClassB(int i) { this.i = i; }
public bool Equals(MyClassB other) { return this.i == other.i; }
}
public class Program
{
public static void Main()
{
var actual1 = new List<MyClassA>() { new MyClassA(1), new MyClassA(2), new MyClassA(3) };
var expected1 = new List<MyClassA>() { new MyClassA(1), new MyClassA(2), new MyClassA(3) };
Console.WriteLine(Enumerable.SequenceEqual(actual1, expected1));
var a1 = new MyClassA(1);
var a2 = new MyClassA(2);
var a3 = new MyClassA(3);
var actual2 = new List<MyClassA>() { a1, a2, a3 };
var expected2 = new List<MyClassA>() { a1, a2, a3 };
Console.WriteLine(Enumerable.SequenceEqual(actual2, expected2));
var actual3 = new List<MyClassB>() { new MyClassB(1), new MyClassB(2), new MyClassB(3) };
var expected3 = new List<MyClassB>() { new MyClassB(1), new MyClassB(2), new MyClassB(3) };
Console.WriteLine(Enumerable.SequenceEqual(actual3, expected3));
var actual4 = new List<MyClassB>() { new MyClassB(1), new MyClassB(2), new MyClassB(3) };
var expected4 = new List<MyClassB>() { new MyClassB(3), new MyClassB(2), new MyClassB(1) };
Console.WriteLine(Enumerable.SequenceEqual(actual4, expected4));
}
}
Output:
False
True
True
False
using System.Linq;
Enumerable.SequenceEqual(a, b);
// or SequenceEqual(a, b, StringComparer.OrdinalIgnoreCase)
See MSDN, also this question.
Perhaps you can use IEnumerable.ExceptOf
http://msdn.microsoft.com/en-us/library/bb300779.aspx
Our perhaps you can use an HashSet and there the intersect method.
http://msdn.microsoft.com/en-us/library/bb293080.aspx
I tend to find the HashSet<T> collection fit for this kind of purpose, cast your collections into HashSet<T> then call SetEquals
I have an Interface [BindControls] which takes data from GUI and store it into a list „ieis”.
After that, Into another class, which sends this data through WebServices, I want to take this data from „ieis” and put it into required by WS Class fields (bottom is a snippet of code)
This is the interface:
void BindControls(ValidationFrameBindModel<A.B> model)
{
model.Bind(this.mtbxTax, (obj, value) =>
{
var taxa = TConvertor.Convert<double>((string)value, -1);
if (taxa > 0)
{
var ieis = new List<X>();
var iei = new X
{
service = new ServiceInfo
{
id = Constants.SERVICE_TAX
},
amount = tax,
currency = new CurrencyInfo
{
id = Constants.DEFAULT_CURRENCY_ID
}
};
ieis.Add(iei);
}
},"Tax");
}
This is the intermediate property:
//**********
class A
{
public B BasicInfo
{
get;
set;
}
class B
{
public X Tax
{
get;
set;
}
}
}
//***********
This is the class which sends through WS:
void WebServiceExecute(SomeType someParam)
{
//into ‚iai’ i store the data which comes from interface
var iai = base.Params.FetchOrDefault<A>( INFO, null);
var convertedObj = new IWEI();
//...
var lx = new List<X>();
//1st WAY: I tried to put all data from ‚Tax’into my local list ‚lx’
//lx.Add(iai.BasicInfo.Tax); - this way is not working
//2nd WAY: I tried to put data separately into ‚lx’
var iei = new X
{
service = new ServiceInfo
{
id = iai.BasicInfo.Tax.service.id
},
amount = iai.BasicInfo.Tax.amount,
currency = new CurrencyInfo
{
id = iai.BasicInfo.Tax.currency.id
}
};
lx.Add(iei);
// but also is not working
Can you help me please to suggest how to implement a way that will fine do the work (take data from ‚ieis’ and put her into ‚lx’).
Thank you so much
As noted in my comment, it looks like iai.BasicInfo.Tax is null, once you find out why that is null your original Add() (#1) will work.