Hierarchical List Conversion For Tree View - c#

I have a list of records that I want to display in a tree view, it has a structure like this.
public class Account
{
public string ac_cd { get; set; }
public string ac_name { get; set; }
public string ac_parent_cd { get; set; }
public string ac_nature { get; set; }
}
I want to convert this into a hierarchical structure, so assuming I have a list that contains the following items,
ac_cd = "01", ac_name = "Cash", ac_parent_cd = "Null", ac_nature = "Asset",
ac_cd = "02", ac_name = "Supplies", ac_parent_cd = "Null", ac_nature = "Asset",
ac_cd = "01.01", ac_name = "ACME Corp Cash", ac_parent_cd = "01", ac_nature = "Asset",
ac_cd = "02.01", ac_name = "ACME Corp Supplies", ac_parent_cd = "02", ac_nature = "Expense",
ac_cd = "02.01.01", ac_name = "ACME Corp Office Supplies", ac_parent_cd = "02.01", ac_nature = "Expense",
I want to convert these items into a hierarchical list like this,
01-Cash
---01.01-ACME Corp Cash
02-Supplies
---02.01-ACME Corp Supplies
------02.01.01-ACME Corp Office Supplies
There can be many number of levels for an account. My code so far can only make a child account up to a single level. Here is the POCO of the hierarchical model.
public class AccountTree
{
public string ac_info { get; set; }
public List<ChildAccount> ac_child { get; set; }
}
public class ChildAccount
{
public string ac_info { get; set; }
}
And here is my code.
List<Account> accountList = new List<Account>();
accountList.Add(new Account { ac_cd = "01", ac_name = "Cash", ac_parent_cd = "", ac_nature = "Asset" });
accountList.Add(new Account { ac_cd = "01.01", ac_name = "Abc Cash", ac_parent_cd = "01", ac_nature = "Asset" });
accountList.Add(new Account { ac_cd = "01.02", ac_name = "Xyz Cash", ac_parent_cd = "01", ac_nature = "Asset" });
List<AccountTree> targetAccountList = new List<AccountTree>();
List<ChildAccount> childAccountList = new List<ChildAccount>();
foreach (var childAccountGrouping in accountList.GroupBy(o => new { o.ac_parent_cd }))
{
if (childAccountGrouping.Key.ac_parent_cd == "")
{
continue;
}
var childAccounts = childAccountGrouping.ToList();
foreach (var childAccount in childAccounts)
{
childAccountList.Add(new ChildAccount { ac_info = childAccount.ac_cd + childAccount.ac_name + childAccount.ac_nature });
}
var parentAccount = (from p in accountList
where p.ac_cd == childAccountGrouping.Key.ac_parent_cd
select p).Single();
AccountTree accountTree = new AccountTree
{
ac_info = parentAccount.ac_cd + parentAccount.ac_name + parentAccount.ac_nature,
ac_child = childAccountList
};
targetAccountList.Add(accountTree);
}
I'm pretty sure I'll have to change this significantly. Would appreciate any assistance.

I would just change the Account class like that:
public class Account
{
public string ac_cd { get; set; }
public string ac_name { get; set; }
public Account ac_parent_cd { get; set; }
public List<Account> ac_children_cd { get; set; }
public string ac_nature { get; set; }
}
now you have easy access to parent and children of all elements

Related

How to convert a list to JSON in C#?

I have a City_State list:
City_State[0].Range="\"city\":\"REDMOND\",\"state\":\"AK\"";
City_State[1].Range="\"city\":\"Alex City\",\"state\":\"
How to convert it into json like below:
var _pairs = new
{
criteria = new { cities = new[] { new { city = "REDMOND", state = "WA" },
new { city = "Alex City", state = "AL" } }
} ;
I tried the code below, but it does not work:
var _pairs = new { criteria = new { cities = new[] { _paged_City_State.ToArray() } } };
If you had these classes:
public class CityStateRaw
{
public string Range { get; set; }
}
public class CityState
{
public string City { get; set; }
public string State { get; set; }
}
The following code would work:
var ranges = new[]
{
new CityStateRaw { Range = "{\"city\":\"REDMOND\",\"state\":\"AK\"}" },
new CityStateRaw { Range = "{\"city\":\"Alex City\",\"state\":\"foo\"}" },
};
var list = ranges
.Select(raw => JsonConvert.DeserializeObject<CityState>(raw.Range))
.ToList();
But if this doesn't match your expectations you should be more concrete about what your exact input and the expected output should be.

Query mongo document array

I have the next mongo document structure :
_id
-countryCode
-keywordID
-name
-displayName
-categories:[Array]
-_id
-name
-position
-canonical
I would like to get all the keywords that are in a specific category only knowing the category's ID. I am using the mongo C# driver but don't know how could I check what's inside that array.
I would like to send a list with the category ID's and get back all the keywords that have a category from that list.
public async Task<List<Keyword>> GetKeywords(List<long> keywordCatIds, string countryCode)
{
var mongoCollection = MongoDatabase.GetCollection<Keyword>("Keywords");
try
{
FilterDefinition<Keyword> mongoFilter = Builders<Keyword>.Filter.In(c=>c.Categories, keywordCatIds);
return await mongoCollection.Find(mongoFilter,null).ToListAsync<Keyword>();
}
catch (Exception ex)
{
Logger.Error(ex, "Multiple ids for Country Code: {0}, ids: {1}", countryCode, string.Join(',', keywordCatIds.Select(s => s)));
return null;
}
}
Your In function looks like a "categories._id" filter in normal mongoDB. Which transitions into an ElemMatch. I created a project which fills the db, than selects
all the keywords that are in a specific category only knowing the category's ID
public class CustomID
{
public string CountryCode { get; set; }
public long KeywordId { get; set; }
public string Name { get; set; }
}
public class Keyword
{
[BsonId]
public CustomID Id { get; set; }
public List<Category> Categories { get; set; }
}
public class Category
{
[BsonId]
public long Id { get; set; }
public string Name { get; set; }
public int Position { get; set; }
}
internal class Program
{
public static IMongoDatabase MongoDatabase { get; private set; }
public static async Task Main()
{
var conventionPack = new ConventionPack
{
new CamelCaseElementNameConvention()
};
ConventionRegistry.Register(
"CustomConventionPack",
conventionPack,
t => true);
var client = new MongoClient();
MongoDatabase = client.GetDatabase("SO");
var ret = await GetKeywords(new List<long> {1L, 2L}, "HU-hu");
// ret is A and B. C is filtered out because no category id of 1L or 2L, D is not HU-hu
}
public static async Task<List<Keyword>> GetKeywords(List<long> keywordCatIds, string countryCode)
{
var mongoCollection = MongoDatabase.GetCollection<Keyword>("keywords");
// be ware! removes all elements. For debug purposes uncomment>
//await mongoCollection.DeleteManyAsync(FilterDefinition<Keyword>.Empty);
await mongoCollection.InsertManyAsync(new[]
{
new Keyword
{
Categories = new List<Category>
{
new Category {Id = 1L, Name = "CatA", Position = 1},
new Category {Id = 3L, Name = "CatC", Position = 3}
},
Id = new CustomID
{
CountryCode = "HU-hu",
KeywordId = 1,
Name = "A"
}
},
new Keyword
{
Categories = new List<Category>
{
new Category {Id = 2L, Name = "CatB", Position = 2}
},
Id = new CustomID
{
CountryCode = "HU-hu",
KeywordId = 2,
Name = "B"
}
},
new Keyword
{
Categories = new List<Category>
{
new Category {Id = 3L, Name = "CatB", Position = 2}
},
Id = new CustomID
{
CountryCode = "HU-hu",
KeywordId = 3,
Name = "C"
}
},
new Keyword
{
Categories = new List<Category>
{
new Category {Id = 1L, Name = "CatA", Position = 1}
},
Id = new CustomID
{
CountryCode = "EN-en",
KeywordId = 1,
Name = "EN-A"
}
}
});
var keywordFilter = Builders<Keyword>.Filter;
var categoryFilter = Builders<Category>.Filter;
var mongoFilter =
keywordFilter.ElemMatch(k => k.Categories, categoryFilter.In(c => c.Id, keywordCatIds)) &
keywordFilter.Eq(k => k.Id.CountryCode, countryCode);
return await mongoCollection.Find(mongoFilter).ToListAsync();
}
}

How to Convert List<T> to BsonArray to save a MongoDB Document

I'm having an Model Class, I need to Save it in a MongoDB Collection.
My Model Class:
public Class Employee
{
public string EmpID { get; set; }
public string EmpName { get; set; }
public List<Mobile> EmpMobile { get; set; }
}
public Class Mobile
{
public string MobID { get; set; }
public string MobNumber { get; set; }
public bool IsPreferred { get; set; }
}
The Values are
Employee EmpInfo = new Employee()
{
EmpID = "100",
EmpName = "John",
EmpMobile = new List<Mobile>()
{
{ MobNumber = "55566610", IsPreferred = true },
{ MobNumber = "55566611", IsPreferred = false },
}
}
BsonDocument _employee = new BsonDocument()
{
{ "Emp_ID", EmpInfo.EmpID },
{ "Emp_Name", EmpInfo.EmpName },
{ "Emp_Mobile", new BsonArray (EmpInfo.EmpMobile.Select(m => new
{
MobID = new ObjectId(),
MobNumber = m.MobNumber,
IsPreferred = m.IsPreferred
})) }
};
var collection = _database.GetCollection<BsonDocument>("EmployeeInfo");
collection.InsertOne(_employee);
I wish to save the above EmpInfo of type Employee in a MongoDB. But I can't able to create a BsonDocument. Kindly assist me is there is anything wrong in the above code. If yes kindly assist me.
there is no need to serialize to bson document
You can use TYPED collection and just insert data
Please see attached code snipet with updated class structure
void Main()
{
// To directly connect to a single MongoDB server
// or use a connection string
var client = new MongoClient("mongodb://localhost:27017");
var database = client.GetDatabase("test");
var collectionEmpInfo = database.GetCollection<Employee>("Employee");
Employee EmpInfo = new Employee
{
EmpID = "100",
EmpName = "John",
EmpMobile = new List<Mobile>
{
new Mobile{ MobNumber = "55566610", IsPreferred = true, MobID = ObjectId.GenerateNewId() },
new Mobile{ MobNumber = "55566611", IsPreferred = false, MobID = ObjectId.GenerateNewId() },
}
};
collectionEmpInfo.InsertOne(EmpInfo);
var empList = collectionEmpInfo.Find(new BsonDocument()).ToList();
empList.Dump(); //dump is used in linqPad
}
public class Employee
{
public ObjectId Id { get; set; }
public string EmpID { get; set; }
public string EmpName { get; set; }
public List<Mobile> EmpMobile { get; set; }
}
public class Mobile
{
public ObjectId MobID { get; set; }
public string MobNumber { get; set; }
public bool IsPreferred { get; set; }
}
In addition to answer above, I can suggest following code if you want to deal directly with Bson for some reason:
BsonDocument _employee = new BsonDocument()
{
{ "Emp_ID", EmpInfo.EmpID },
{ "Emp_Name", EmpInfo.EmpName },
{ "Emp_Mobile", BsonArray.Create(EmpInfo.EmpMobile.Select(m => new BsonDocument()
{
{ "MobID" , new ObjectId() },
{ "MobNumber", m.MobNumber },
{ "IsPreferred", m.IsPreferred }
})) }
};
The reason of the error you've got is that BsonArray.Create creates an array of values, not an array of objects. See this question for details.

Linq : Comparing 1 Child Collection to (Aggregated) ChildCollection(s)

I have a Linq question: (DotNet Framework 4.0)
I have the following classes:
public class Employee
{
public Guid? EmployeeUUID { get; set; }
public string SSN { get; set; }
}
public class JobTitle
{
public Guid? JobTitleSurrogateKey { get; set; }
public string JobTitleName { get; set; }
}
public class EmployeeToJobTitleMatchLink
{
public EmployeeToJobTitleMatchLink()
{
this.TheJobTitle = new JobTitle() { JobTitleSurrogateKey = Guid.NewGuid(), JobTitleName = "SomeJobTitle:" + Guid.NewGuid().ToString("N") };
}
public Guid LinkSurrogateKey { get; set; }
/* Related Objects */
public Employee TheEmployee { get; set; }
public JobTitle TheJobTitle { get; set; }
}
public class Organization
{
public Organization()
{
this.Links = new List<EmployeeToJobTitleMatchLink>();
}
public int OrganizationSurrogateKey { get; set; }
public ICollection<EmployeeToJobTitleMatchLink> Links { get; set; }
}
In my code below, I can compare 2 child-collections and get the results I need (in "matches1".
Here I am using the "SSN" string property to compare and find the overlaps. And the Console.Write for matches1 works as I expect.
What I don't know how to do is compare the first child collection (org10) to all the children in (allOtherOrgsExceptOrg10 (all the Organizations and all the Links of these Organizations )
The commented out code shows kinda what I'm trying to do, one of my many feeble attempts today.
But basically, match2 would be populated with all the SSN overlaps...but comparing org10 with allOtherOrgsExceptOrg10, all their "Links", and their Employee.SSN's.
org10 overlaps with org20 with "AAA", so match2 would contain "AAA". and org10 overlaps with org30 with "BBB" so match2 would contain "BBB".
Organization org10 = new Organization();
org10.OrganizationSurrogateKey = 10;
Employee e11 = new Employee() { SSN = "AAA", EmployeeUUID = new Guid("AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA") };
EmployeeToJobTitleMatchLink link11 = new EmployeeToJobTitleMatchLink();
link11.TheEmployee = e11;
org10.Links.Add(link11);
Employee e12 = new Employee() { SSN = "BBB", EmployeeUUID = new Guid("BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB") };
EmployeeToJobTitleMatchLink link12 = new EmployeeToJobTitleMatchLink();
link12.TheEmployee = e12;
org10.Links.Add(link12);
Organization org20 = new Organization();
org20.OrganizationSurrogateKey = 20;
Employee e21 = new Employee() { SSN = "AAA", EmployeeUUID = new Guid("AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA") };
EmployeeToJobTitleMatchLink link21 = new EmployeeToJobTitleMatchLink();
link21.TheEmployee = e21;
org20.Links.Add(link21);
Employee e22 = new Employee() { SSN = "CCC", EmployeeUUID = new Guid("CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC") };
EmployeeToJobTitleMatchLink link22 = new EmployeeToJobTitleMatchLink();
link22.TheEmployee = e22;
org20.Links.Add(link22);
Organization org30 = new Organization();
org30.OrganizationSurrogateKey = 30;
Employee e31 = new Employee() { SSN = "BBB", EmployeeUUID = new Guid("BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB") };
EmployeeToJobTitleMatchLink link31 = new EmployeeToJobTitleMatchLink();
link31.TheEmployee = e31;
org30.Links.Add(link31);
Employee e32 = new Employee();
e32.SSN = "ZZZ";
EmployeeToJobTitleMatchLink link32 = new EmployeeToJobTitleMatchLink();
link32.TheEmployee = e32;
org30.Links.Add(link32);
IList<Organization> allOtherOrgsExceptOrg10 = new List<Organization>();
/* Note, I did not add org10 here */
allOtherOrgsExceptOrg10.Add(org20);
allOtherOrgsExceptOrg10.Add(org30);
IEnumerable<EmployeeToJobTitleMatchLink> matches1 =
org10.Links.Where(org10Link => org20.Links.Any(org20Link => org20Link.TheEmployee.SSN.Equals(org10Link.TheEmployee.SSN, StringComparison.OrdinalIgnoreCase)));
IEnumerable<EmployeeToJobTitleMatchLink> matches2 = null;
//org10.Links.Where(org10Link => ( allOtherOrgs.Where ( anyOtherOrg => anyOtherOrg.Links.Any(dbSideChild => dbSideChild.TheEmployee.SSN == org10Link.TheEmployee.SSN)) );
if (null != matches1)
{
foreach (EmployeeToJobTitleMatchLink link in matches1)
{
Console.WriteLine(string.Format("matches1, SSN = {0}", link.TheEmployee.SSN));
}
}
if (null != matches2)
{
foreach (EmployeeToJobTitleMatchLink link in matches2)
{
Console.WriteLine(string.Format("matches2, SSN = {0}", link.TheEmployee.SSN));
}
}
matches2 =
allOtherOrgsExceptOrg10.SelectMany(x => x.Links)
.Where(x => org10.Links.Select(o => o.TheEmployee.SSN).Contains(x.TheEmployee.SSN));
You can use the SelectMany on the allOther collection to select all Links over all org's. Then check if any SSN is inside the org10 List.
See: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.selectmany(v=vs.100).aspx
You can use SelectMany to flatten out the collection and then use it just like you have for matches1
IEnumerable<EmployeeToJobTitleMatchLink> matches2 =
org10.Links.Where(
org10Link =>
allOtherOrgsExceptOrg10.SelectMany(allOtherOrgs => allOtherOrgs.Links).Any(
anyOtherLink =>
anyOtherLink.TheEmployee.SSN.Equals(org10Link.TheEmployee.SSN, StringComparison.OrdinalIgnoreCase)));
The SelectMany will make it seem like one IEnumerable instead of and IEnumerable of an IEnumerable.

How can I modify my code to get data from an array of objects in C#?

I have the following class:
public partial class Content
{
public int ContentId { get; set; }
public int ContentTypeId { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual byte[] Version { get; set; }
public int SubjectId { get; set; }
public virtual Subject Subject { get; set; }
}
and the following code:
var myData = new[] {
"Content 1",
"Content 2",
"Content 3"
};
var contents = myData.Select(e => new Content
{
Title = e,
Text = "xx",
ModifiedDate = DateTime.Now
}
How can I modify this so I can specify both the "Title" and some small sample "Text" in the myData array. I was thinking about using an array of objects but I am not quite sure how to set this up.
Here is the syntax for that:
var myData = new List<Content>
{
new Content{Title = "Content 1", Text = "xx", ModifiedDate = DateTime.Now},
new Content{Title = "Content 2", Text = "AB", ModifiedDate = DateTime.Now},
new Content{Title = "Content 3", Text = "CC", ModifiedDate = DateTime.Now}
};
How about you use Tuple?
var myDatas = new[]
{
new Tuple<string, string, DateTime>("Title", "Example", DateTime.Now),
new Tuple<string, string, DateTime>("Title2", "Example", DateTime.Now.AddDays(-1)),
new Tuple<string, string, DateTime>("Title3", "Example", DateTime.Now.AddDays(1))
};
var contents = myDatas.Select(e => new Content
{
Title = e.Item1,
Text = e.Item2,
ModifiedDate = DateTime.Now
});

Categories

Resources