Fill up the list class object through a function - c#

I've created a class for List and by creating an object the constructor should call the function inside it and recursively go through all the database (H_Table/Table) and return List with all hierarchy structure in it.
How to do it, so, it'd go through all the elements and not just rewriting the same one when going through foreach and if/else statements?
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Tree_List.Models;
using System.Data.Entity;
namespace Tree_List.Controllers
{
public class ListController : Controller
{
// GET: List
private Models.ListDBEntities1 db_connection = new Models.ListDBEntities1();
public ActionResult Index()
{
var Hierarchy = db_connection.H_Table;
Element Item = new Element(Hierarchy, null);
return View(Item);
}
}
public partial class Element
{
public int ID { get; set; }
public string NAME { get; set; }
public List<Element> CHILDS { get; set; }
public Element(DbSet<H_Table> Table, int? ParentID)
{
PopulateList(Table, ParentID);
}
public List<Element> PopulateList (DbSet<H_Table> Table, int? ParentI)
{
List<Element> temp = new List<Element>();
foreach (var root in Table)
{
if (root.PARENT_ID == null)
{
ID = root.ID;
NAME = root.NAME;
foreach (var child in Table)
{
if (child.PARENT_ID == ID)
{
ID = child.ID;
NAME = child.NAME;
}
}
}
}
return temp;
}
}
}

Can you use this. it will return list of all element
List<Element> = db_connection.H_Table.Select(s=>new Element {
ID = s.ID,
NAME =s.NAME
}).ToList();

Related

Delete a record by matching Value

I have a dictionary where values are stored in the following format -
userID, empDetails
For example,
1234, 'empName,jobDesc,CardNumber,Type'
I have to compare this information with another set of information such that -
If entered userId is present in the above dictionary, then remove this record from the dictionary.
If entered CardNumber is present (here userId is not known) in the above dictionary, then remove this record from the dictionary.
The first condition is simple and can be done by
dictionary.Remove(key)
But I am confused as to how would I implement the second condition. I want something like
if(CardNumber.PresentinAboveDictionary)
then
Remove that record
I know we can compare a partial string in a key like this, but I want to remove the record.
Check if any part of a hashtable value contains certain string c#
Assuming the employment details in your dictionary are a string in the specified format you would need to:
Search the values within the dictionary
Parse/Split the values to get the card numbers
Check the card numbers to see if they match the card number you are checking
Return the key value pair when a match occurs
Remove the entry for the key in the returned key value pair
Example code for the solution:
var dictionary = new Dictionary<int, string>() { { 1, "empName,jobDesc,124124134,Type" } };
var cardNumber = 124124134;
var entry = dictionary.FirstOrDefault(x => DoEmploymentDetailsContainCardNumber(x.Value, cardNumber));
if (!entry.Equals(default(KeyValuePair<int, string>)))
{
dictionary.Remove(entry.Key);
}
Method that checks if card number is present in employment details:
private static bool DoEmploymentDetailsContainCardNumber(string empDetails, int cardNumber)
{
var splitEmpDetails = empDetails.Split(',');
var empDetailsCardNumber = splitEmpDetails[2];
return empDetailsCardNumber == cardNumber.ToString();
}
Instead of Dictionary you can use a strongly typed List
Use the Linq builtin Remove method
Use Parallel.ForEach, iterate the list and remove the item (beware, takes more time)
pseudo code:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using System.Collections;
namespace ConsoleApp4
{
public class Employee
{
public Employee(int userID, string empDetails)
{
string[] props = empDetails.Split(new char[] { ',' }, StringSplitOptions.None);
this.userID = userID;
this.empName = props[0];
this.jobDesc = props[1];
this.CardNumber = props[2];
this.Type = props[3];
}
public int userID { get; set; }
public string empName { get; set; }
public string jobDesc { get; set; }
public string CardNumber { get; set; }
public string Type { get; set; }
}
public class MyCustomList : List<Employee>
{
public void Add(int userID, string empDetails)
{
this.Add(new Employee(userID, empDetails));
}
public bool Remove(string CardNumber)
{
bool found = false ;
Parallel.ForEach(this,
(i, state) =>
{
if (i.CardNumber == CardNumber)
{
this.Remove(i);
state.Break();
}
});
return found;
}
public bool RemoveV2(string CardNumber)
{
bool found = false;
if (this.Any(x => x.CardNumber == CardNumber))
{
this.Remove(this.Where(x => x.CardNumber == CardNumber).First());
found = true;
}
return found;
}
}
class Program
{
static void Main(string[] args)
{
var dict = new MyCustomList();//userID, empDetails list
dict.Add(12341, "empName1,jobDesc,CardNumber1,Type");
dict.Add(12342, "empName2,jobDesc,CardNumber2,Type");
dict.Add(12343, "empName3,jobDesc,CardNumber3,Type");
dict.Add(12344, "empName4,jobDesc,CardNumber4,Type");
dict.Add(12345, "empName5,jobDesc,CardNumber5,Type");
dict.Add(12346, "empName6,jobDesc,CardNumber6,Type");
dict.Add(12347, "empName7,jobDesc,CardNumber7,Type");
dict.Add(12348, "empName8,jobDesc,CardNumber8,Type");
//remove CardNumber5
dict.Remove("CardNumber5");
Console.Write(dict);
}
}
}
you can follow the simple approach to remove the key by using a loop here.
Here I am assuming that there is no key with a value of -1 in the dictionary.
int keyToRemove = -1;
foreach (var entry in dictionary)
{
if (entry.Value.Contains(CardNumber))
{
keyToRemove = entry.Key;
break;
}
}
if (keyToRemove != -1)
{
dictionary.Remove(keyToRemove);
}
This is possibly overkill and is not optimised for reading the full dataset repeatedly but it is considerably faster than the accepted solution. I put together a test of the solution below which did the following:
Generated 1,000,000 data rows with unique IDs and card numbers (the solution would also work if the card numbers were not unique)
Randomly removed 100,000 data items by ID and 100,000 data items by card number
Generated a list of the remaining data items
The process took around 75 seconds.
I then tried to repeat steps 1) and 2) using the accepted answer - after around 10 minutes it's about 7% of the way through removing data items. Therefore I think the solution below is around 2 orders of magnitude faster for this type of operation.
There are probably better doubley linked list implementations out there but I am not too familiar with any of them.
namespace Question
{
public class EmployeeCollection
{
private readonly Dictionary<int, ListNode<EmployeeDetails>> _idDictionary = new();
private readonly Dictionary<string, Dictionary<int, EmployeeDetails>> _cardNumberDictionary = new();
private readonly LinkedList<EmployeeDetails> _list = new();
public void AddEmployee(EmployeeDetails details)
{
var node = new ListNode<EmployeeDetails>(details);
_list.AddToStart(node);
_idDictionary.Add(details.Id, node);
if(!_cardNumberDictionary.ContainsKey(details.CardNumber))
{
_cardNumberDictionary.Add(details.CardNumber, new Dictionary<int, EmployeeDetails>());
}
_cardNumberDictionary[details.CardNumber].Add(details.Id, details);
}
public void RemoveById(int id)
{
if (_idDictionary.TryGetValue(id, out var node))
{
_idDictionary.Remove(id);
_list.Remove(node);
var list = _cardNumberDictionary[node.Value.CardNumber];
list.Remove(id);
if(list.Count == 0)
{
_cardNumberDictionary.Remove(node.Value.CardNumber);
}
}
}
public void RemoveByCardNumber(string cardNumber)
{
if (_cardNumberDictionary.TryGetValue(cardNumber, out var employees))
{
_cardNumberDictionary.Remove(cardNumber);
foreach (var employee in employees)
{
if (_idDictionary.TryGetValue(employee.Key, out var node))
{
_list.Remove(node);
}
}
}
}
public IEnumerable<EmployeeDetails> Employees => _list.GetAllValues();
public EmployeeDetails? GetById(int id)
{
if(_idDictionary.ContainsKey(id))
{
return _idDictionary[id].Value;
}
return null;
}
}
public class EmployeeDetails
{
public int Id { get; init; }
public string Name { get; init; }
public string JobDescription { get; init; }
public string CardNumber { get; init; }
public string Type { get; init; }
public static EmployeeDetails FromData(int id, string details)
{
var parts = details.Split(',');
return new EmployeeDetails
{
Id = id,
Name = parts[0],
JobDescription = parts[1],
CardNumber = parts[2],
Type = parts[3],
};
}
}
public class LinkedList<T>
{
public int Count { get; private set; }
private ListNode<T>? Start { get; set; }
private ListNode<T>? End { get; set; }
public bool IsEmpty => Count == 0;
public void AddToStart(ListNode<T> node)
{
ArgumentNullException.ThrowIfNull(nameof(node));
node.Next = null;
node.Previous = null;
if (IsEmpty)
{
Start = End = node;
}
else
{
Start!.Previous = node;
node.Next = Start;
Start = node;
}
Count++;
}
public void Remove(ListNode<T> node)
{
if (node != Start)
{
node.Previous!.Next = node.Next;
}
else
{
Start = node.Next;
}
if (node != End)
{
node.Next!.Previous = node.Previous;
}
else
{
End = node.Previous;
}
Count--;
}
public IEnumerable<T> GetAllValues()
{
var counter = Start;
while (counter != null)
{
yield return counter.Value;
counter = counter.Next;
}
}
}
public class ListNode<T>
{
public T Value { get; }
public ListNode<T>? Previous { get; set; }
public ListNode<T>? Next { get; set; }
public ListNode(T value)
{
Value = value;
}
}
}
you can do something like this.
var recordsToRemove = dictionary.Where(x => x.Value.Contains("what you are looking for"))
.ToList();
if (recordsToRemove.Any())
{
foreach (var record in recordsToRemove)
{
dictionary.Remove(record.Key);
}
}

How to print sorted list?

I'm trying to sort a list of cars by their price range. Currently I'm unsure if I've even sorted it correctly with IComparable, and I can't figure out how I print the list after it's sorted, I can only print them in the order they were declared.
using System;
using System.Collections.Generic;
namespace Interface1
{
class Program
{
class Car : IComparable<Car>
{
public string Make { get; set; }
public string Model { get; set; }
public double Price { get; set; }
public int CompareTo(Car car)
{
return this.Price.CompareTo(car.Price);
}
static void Main(string[] args)
{
List<Car> cars = new List<Car>()
{
new Car(){Make = "Skoda", Model = "Fabia", Price = 50000},
new Car(){Make = "Skoda", Model = "Octavia", Price = 60000},
new Car(){Make = "Nissan", Model = "Juke", Price = 45000 }
};
foreach (var car in cars)
Console.WriteLine(car.Price);
}
}
}
}
Have I done the sorting correctly? How can I print it properly?
Change this line as so
foreach (var car in cars.OrderBy(x => x.Price))
Console.WriteLine(car.Price);
You can add a different comparer as well in the OrderBy function.

Using a Parameter to Call a Class in C#

I have got a method with a single parameter of string class that I need to use to access another class in my project.
The following will be what I want it to do. Note that this syntax gives errors.
public string getId(string name) {
string Id = name.GetId();
return Id;
}
Assuming that the user enters "Joe" as the name, one would go to the class Joe.cs, which looks like this.
public class Joe {
public string Id = 32;
public string GetId() {
return Id;
}
}
What I want to happen here is for the first method to be able to get the GetId method from Joe if Joe is entered as a parameter. How would I do this? Thank you all.
This might point you in a better direction
The idea is to have a class called User that holds user information (funnily enough)
This way you can have a list of users (not a class for each one), as such you can easily look up a user and mess with them as much as you want
public class User
{
public string UserName { get; set; }
public string FavoriteColor { get; set; }
}
public class Program
{
// A List to hold users
private static List<User> _users = new List<User>();
private static void Main(string[] args)
{
// lets add some people
_users.Add(new User() { UserName = "Bob",FavoriteColor = "Red" });
_users.Add(new User() { UserName = "Joe", FavoriteColor = "Green" });
_users.Add(new User() { UserName = "Fred", FavoriteColor = "Blue" });
// use a linq query to find someone
var user = _users.FirstOrDefault(x => x.UserName == "Bob");
// do they exist?
if (user != null)
{
// omg yay, gimme teh color!
Console.WriteLine(user.FavoriteColor);
}
}
}
Output
Red
You can take it a step further and ask the user to look up other users (what a time to be a alive!)
Console.WriteLine("Enter a user (case sensitive)");
var userName = Console.ReadLine();
var user = _users.FirstOrDefault(x => x.UserName == userName);
if (user != null)
{
Console.WriteLine(user.FavoriteColor);
}
else
{
Console.WriteLine("Game over, you failed");
}
Console.ReadLine();
You could build a Class that can contain the details you want to store, then build a Manager class that exposes public methods that can extract informations from the stored objects:
public class Friend : IComparable<Friend>
{
public Friend() { }
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int FriendshipLevel { get; set; }
int IComparable<Friend>.CompareTo(Friend other)
{
if (other.FriendshipLevel > this.FriendshipLevel) return -1;
else return (other.FriendshipLevel == this.FriendshipLevel) ? 0 : 1;
}
}
public class MyFriends : List<Friend>
{
public MyFriends() { }
public int? GetID(string FriendName)
{
return this.Where(f => f.FirstName == FriendName).FirstOrDefault()?.ID;
}
public Friend GetFriendByID(int FriendID)
{
return this.Where(f => f.ID == FriendID).FirstOrDefault();
}
}
Build a sample class:
MyFriends myFriends = new MyFriends()
{
new Friend() { ID = 32, FirstName = "Joe", LastName = "Doe", FriendshipLevel = 100},
new Friend() { ID = 21, FirstName = "Jim", LastName = "Bull", FriendshipLevel = 10},
new Friend() { ID = 10, FirstName = "Jack", LastName = "Smith", FriendshipLevel = 50},
};
Then you can extract informations on single/multiple objects using the public methods of the "Manager" class:
int? ID = myFriends.GetID("Joe");
if (ID.HasValue) // Friend Found
Console.WriteLine(ID);
//Search a friend by ID
Friend aFriend = myFriends.GetFriendByID(32);
if (aFriend != null)
Console.WriteLine($"{aFriend.FirstName} {aFriend.LastName}");
Or you can use LINQ to get/aggregate the required informations directly if there isn't a public method that fits:
// Get your best friends using LINQ directly
List<Friend> goodFriends = myFriends.Where(f => f.FriendshipLevel > 49).ToList();
goodFriends.ForEach((f) => Console.WriteLine($"{f.FirstName} {f.LastName}"));
//Best friend
Friend bestFriend = myFriends.Max();
With respect to your Question : GetId method from Joe if Joe is entered as a
parameter.
You can achieve that in the following ways also:
2. Method Using Named Method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem
{
// Simple Model Class.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
// Delegate.
public delegate string PersonHandler(Person person);
static void Main(string[] args)
{
List<Person> _persons = new List<Person>()
{
new Person(){Id=1,Name="Joe"},
new Person(){Id=2,Name="James"},
new Person(){Id=3,Name="Nick"},
new Person(){Id=4,Name="Mike"},
new Person(){Id=5,Name="John"},
};
PersonHandler _personHandler = new PersonHandler(GetIdOfPerson);
IEnumerable<string> _personIds = _persons.Select(p => _personHandler.Invoke(p));
foreach (var id in _personIds)
{
Console.WriteLine(string.Format("Id's : {0}", id));
}
}
// This is the GetId Method.
static string GetIdOfPerson(Person person)
{
string Id = person.Id.ToString();
return Id;
}
}
}
2. Method Using Anonymous Moethod.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem
{
// Simple Model Class.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
// Delegate.
public delegate string PersonHandler(Person person);
static void Main(string[] args)
{
List<Person> _persons = new List<Person>()
{
new Person(){Id=1,Name="Joe"},
new Person(){Id=2,Name="James"},
new Person(){Id=3,Name="Nick"},
new Person(){Id=4,Name="Mike"},
new Person(){Id=5,Name="John"},
};
PersonHandler _personHandler = delegate(Person person)
{
string id = person.Id.ToString();
return id;
};
// Retrieving all person Id's.
IEnumerable<string> _personIds = _persons.Select(p => _personHandler.Invoke(p));
foreach (var id in _personIds)
{
Console.WriteLine(string.Format("Id's : {0}", id));
}
}
}
}
2. Method Using a Lambda Expression.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem
{
// Simple Model Class.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
// Delegate.
public delegate string PersonHandler(Person person);
static void Main(string[] args)
{
List<Person> _persons = new List<Person>()
{
new Person(){Id=1,Name="Joe"},
new Person(){Id=2,Name="James"},
new Person(){Id=3,Name="Nick"},
new Person(){Id=4,Name="Mike"},
new Person(){Id=5,Name="John"},
};
PersonHandler _personHandler = (Person person) => person.Id.ToString();
IEnumerable<string> _personIds = _persons.Select(p => _personHandler.Invoke(p));
foreach (var id in _personIds)
{
Console.WriteLine(string.Format("Id's : {0}", id));
}
}
}
}
Output:

Inserting and MultiMapping using Dapper.Contrib

What I am attempting to do, is to be able to use complex objects both for retrieval and for writing back to the database.
For example, I have two classes
[Table("Children")]
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
}
[Table("Parents")]
public class Parent
{
public int Id { get; set; }
public string Data { get; set; }
public List<Child> Children { get; set; }
public Parent()
{
Children = new List<Child>();
}
}
I populate the Parent object using the method below
public List<Parent> GetAll()
{
var parents = new List<Parent>();
using (SQLiteConnection conn = new SQLiteConnection(sqlConnectionString))
{
string sql = $#"
SELECT * From Parents;
SELECT * FROM Children;
;";
var results = conn.QueryMultiple(sql);
parents = results.Read<Parent>().ToList();
var children = results.Read<Child>();
foreach (var parent in parents)
{
parent.Children = children.Where(a => a.ParentId == parent.Id).ToList();
}
}
return parents;
}
My Question now that I have my populated object, say I want to make changes to Parent including adding/updating/remove values from Parent.Children
This is my first pass at an update method, but I recognize there are issues here, such as making the determination to update or insert based on the child Id being zero or not, as well as this being a bit verbose.
Is there way, and am I missing some functionality of Dapper or Dapper.Contrib that would provide helper methods to make this process easier?
public bool Update(Parent parent)
{
bool result = true;
using (SQLiteConnection conn = new SQLiteConnection(sqlConnectionString))
{
conn.Open();
using (var tran = conn.BeginTransaction())
{
try
{
if (!conn.Update<Parent>(parent))
{
result = false;
}
foreach (var element in parent.Children)
{
if (element.Id == default(int))
{
conn.Insert<Child>(element);
}
else
{
if (!conn.Update<Child>(element))
{
result = false;
}
}
}
tran.Commit();
}
catch(Exception ex)
{
//logger.Error(ex,"error attempting update");
tran.Rollback();
throw;
}
}
}
return result;
}
Sadly, given how poor the response was to this question, and Dapper.Contrib questions in general. I've decided to dump Dapper and switch to an ORM that better suites my needs. Thanks for all those that offered suggestions.

bug in my Recursive method

I'm having a problem with my recursive method. This method is not behaving as i wish it to behave.
What i am trying to do is to is to get a sorted list of all the categories i have in my database, those lists contains a list of childs named ChildList, and i am trying to make a method that would recursively add right child to the rightful parent.
On 3 levels down it behaves exactly as i want, it adds a Child to the childlist of CategoryViewModel. after that, it tends to make duplicate childs which i dont want it to.
For example, you have
Root - Root has Electronics as child,
Electronics has Telephones as child,
Telephone has Mobilephones, here is where my recursive method duplicate the child, making 2 Mobilephones, and if i have a category Iphone under Mobilephones it would make 3 Iphone-categorychildrens to each Mobilephone. The Iphone categories doesent have any children and the list is 0. but i bet if it would have, each iphone would have 4 childs of that category.
here is my code
namespace GUI.Controllers
{
public class HomeController : Controller
{
private readonly IRepository<Category> _repo;
private static List<CategoryViewModel> _sources;
public HomeController(IRepository<Category> repo)
{
_repo = repo;
}
public HomeController()
: this(new Repository<Category>())
{
}
public ViewResult Index()
{
var items = _repo.GetAll().ToList();
var sortedList = new CategoryViewModel();
_sources = items.Select(c => new CategoryViewModel
{
Id = c.Id,
Name = c.Name,
Parent = c.Parent.HasValue ? c.Parent.Value : (Guid?) null,
Products = c.Product.ToList(),
ChildList = new List<CategoryViewModel>()
}).ToList();
_sources = _sources.OrderBy(o => o.Parent).ToList();
var root = _sources.First();
sortedList.Id = root.Id;
sortedList.Name = root.Name;
sortedList.Parent = null;
sortedList.ChildList = _sources.Where(o => o.Parent != null && o.Parent == root.Id).ToList();
foreach (var l in _sources)
{
if(l.Parent == null)
continue;
l.ChildList = _sources.Where(o => o.Parent != null && o.Parent == l.Id).ToList();
if (l.ChildList.Any())
AddItem(l.ChildList, ref sortedList);
}
return View(sortedList);
}
private static void AddItem(List<CategoryViewModel> children, ref CategoryViewModel sortedList)
{
foreach (var child in children)
{
var childs = _sources.Where(o => o.Parent != null && o.Parent == child.Id).ToList();
foreach (var c in childs)
{
child.ChildList.Add(c);
}
if (child.ChildList.Any())
AddItem(child.ChildList, ref sortedList);
}
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using ClassLibrary.Entities;
namespace GUI.Models
{
public class CategoryViewModel
{
[Required]
public string Name { get; set; }
[Required]
public string SearchString { get; set; }
public Guid Id { get; set; }
public Guid? Parent { get; set; }
public string ParentName { get; set; }
public List<Product> Products { get; set; }
public List<CategoryViewModel> ChildList { get; set; }
}
}
Ok i found out what the solution to my problem is;
My recursive method was overflow of code, i went too deep without understanding how to practicly use the recursive method. as they say; one thing led to another and i eventually deleted my AddItem Method, it turns out that my lambda expression sorted out the lists for me in the right collection of lists; the final code looks alot more clean and is alot smaller now;
public ViewResult Index()
{
var items = _repo.GetAll().ToList();
var categories = items.Select(c => new CategoryViewModel
{
Id = c.Id,
Name = c.Name,
Parent = c.Parent.HasValue ? c.Parent.Value : (Guid?) null,
Products = c.Product.ToList(),
ChildList = new List<CategoryViewModel>()
}).OrderBy(o => o.Parent).ToList();
var sortedCategories = categories.First();
sortedCategories.ChildList = categories.Where(o => o.Parent != null && o.Parent == sortedCategories.Id).ToList();
foreach (var l in categories.Where(l => l.Parent != null))
{
l.ChildList = categories.Where(o => o.Parent != null && o.Parent == l.Id).ToList();
}
return View(sortedCategories);
}

Categories