I got 3 tables like below which reference the ID column's:
#Table 1
DepID NAME
1 Dep1
2 Dep2
3 Dep3
#Table 2
RoleID Name DepID
11 A1 1
12 A2 2
13 A3 1
14 A4 3
15 A5 3
#Table 3
ID Name RoleID
21 B1 11
23 B2 14
24 B3 11
Output
Menu
Dep1
A1B1B3
A3
Dep2A2
Dep3
A4B2
A5
I have tried using foreach loop, below is example:
StringBuilder objstr = new StringBuilder();
List<Parant> objpmenu = new List<Parant>();
List<Child> objcmenu = new List<Child>();
List<NestedChild> objnmenu = new List<NestedChild>();
objpmenu = GetParantMenu();
objcmenu = GetChildMenu();
objnmenu = GetNestedChildMenu();
objstr.Append("<ul id=\"drop-nav\">");
foreach (MenuParant _pitem in objpmenu)
{
objstr.Append("<li ><a href='" + _pitem.Url + "'><span >" +_pitem.MenuName + "</span></a>");
var childitem = objcmenu.Where(m => m.ParentId == _pitem.Id).ToList();
if (childitem.Count > 0)
{
objstr.Append("<ul>");
foreach (var _citem in childitem)
{
objstr.Append("<li ><a id='asubservice" + _citem.ChildId + "' href='" + _citem.ChildUrl + "'><span>" + _citem.ChildName + "</span></a></li>");
var NestedChildItem = objnmenu.Where(s => s.ChildId == _citem.ChildId).ToList();
if (NestedChildItem.Count > 0)
{
objstr.Append("<ul>");
foreach (var _nitem in NestedChildItem)
{
objstr.Append("<li><a href='" + _nitem.NestedChildUrl + "'>" + _nitem.NestedChildName + "</a></li>");
}
objstr.Append("</ul>");
}
}
objstr.Append("</ul>");
}
objstr.Append("</li>");
}
objstr.Append("</ul>");
divmenu.InnerHtml = objstr.ToString();
Please help me to generate menu with HTML content using Linq.
ThanQ in Advance
Normally where you have a n level hierarchy you would use a recursive method like code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication71
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable("DepID") ;
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("NAME", typeof(string));
dt.Columns.Add("PARENTID", typeof(int));
dt.Rows.Add(new object[] { 1, "Dep1"});
dt.Rows.Add(new object[] { 2, "Dep2"});
dt.Rows.Add(new object[] { 3, "Dep3"});
dt.Rows.Add(new object[] { 11, "A1", 1});
dt.Rows.Add(new object[] { 12, "A2", 2});
dt.Rows.Add(new object[] { 13, "A3", 1});
dt.Rows.Add(new object[] { 14, "A4", 3});
dt.Rows.Add(new object[] { 15, "A5", 3});
dt.Rows.Add(new object[] { 21, "B1", 11});
dt.Rows.Add(new object[] { 23, "B2", 14});
dt.Rows.Add(new object[] { 24, "B3", 11});
Node node = new Node();
node.Load(dt);
}
}
public class Node
{
public static Node root = new Node();
public string name { get; set; }
public int? id { get; set; }
public List<Node> children { get; set; }
public void Load(DataTable dt)
{
LoadRecursive(dt, null, root);
}
public void LoadRecursive(DataTable dt, int? parent, Node node)
{
foreach (DataRow row in dt.AsEnumerable().Where(x => x.Field<int?>("PARENTID") == parent))
{
if (node.children == null) node.children = new List<Node>();
Node newChild = new Node();
node.children.Add(newChild);
newChild.name = row.Field<string>("NAME");
newChild.id = row.Field<int>("ID");
LoadRecursive(dt, newChild.id, newChild);
}
}
}
}
You should get rid of the string concatenation as first thing. We have a couple of frameworks to take care of gory details. One such is called ASP.Net.
Once you have done that, make use of Repeater control to generate markup. Learn about databinding in asp.net and use that to generate your menu instead of manually looping through all the data.
If you need help generating those Repeater controls I talk about, I'll be more than happy to guide you further.
Related
I have a table as follows
I have a query that runs each day to find anything that's 5 days old or greater and has a status of "In Progress" and set the status to "Declined".
What I need to be able to do is also set the status to "Declined" for anything with a Linked_ID (child) where the ID (Parent) has been changed.
So in the table I already set ID 1 to "Declined" but I also need to set ID's 2,3,4,8 and 10 to "Declined"
Below is what I have so far, any support would be amazing and really helpful
var Process = from a in db.Table1
where a.Status == "In Progress" && a.Date_Created = DateTime.Now.AddDays(-5)
select a;
foreach (Table1 a in Process)
{
a.Status = "Declined";
}
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Declined declined = new Declined();
declined.Query(DateTime.Now.AddDays(1));
}
}
public class Declined
{
DataTable dt;
public Declined()
{
dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Status", typeof(string));
dt.Columns.Add("Date Created", typeof(DateTime));
dt.Columns.Add("Link_ID", typeof(int));
dt.Rows.Add(new object[] { 1, "In Progress", new DateTime(2020, 9, 25) });
dt.Rows.Add(new object[] { 2, "Completed", new DateTime(2020, 9, 28),1 });
dt.Rows.Add(new object[] { 3, "In Progress", new DateTime(2020, 9, 28),1 });
dt.Rows.Add(new object[] { 4, "In Progress", new DateTime(2020, 9, 28),1 });
dt.Rows.Add(new object[] { 5, "In Progress", new DateTime(2020, 9, 28),2 });
dt.Rows.Add(new object[] { 6, "In Progress", new DateTime(2020, 9, 28),3 });
dt.Rows.Add(new object[] { 7, "In Progress", new DateTime(2020, 9, 28) });
dt.Rows.Add(new object[] { 8, "In Progress", new DateTime(2020, 9, 28),1 });
dt.Rows.Add(new object[] { 9, "In Progress", new DateTime(2020, 9, 28) });
dt.Rows.Add(new object[] { 10, "In Progress", new DateTime(2020, 9, 28),1 });
}
public void Query(DateTime date)
{
List<DataRow> rows = dt.AsEnumerable().Where(x => (x.Field<string>("Status") == "In Progress") && (date.Date.Subtract(x.Field<DateTime>("Date Created")).Days > 5)).ToList();
foreach(DataRow row in rows)
{
if (rows.Count > 0) ChangeChildren_Recursive(row, row.Field<DateTime>("Date Created"));
}
}
public void ChangeChildren_Recursive(DataRow row, DateTime date)
{
int id = row.Field<int>("ID");
DateTime rowDate = row.Field<DateTime>("Date Created").Date;
string status = row.Field<string>("Status");
if((status == "In Progress") && (date != rowDate)) row["Status"] = "Declined";
List<DataRow> children = dt.AsEnumerable().Where(x => (x.Field<int?>("Link_ID") == id) && (x.Field<int?>("Link_ID") != null)).ToList();
foreach (DataRow childRow in children)
{
ChangeChildren_Recursive(childRow, date);
}
}
}
}
I have a data table and I need to merge the cells with the same values in the columns IPC and Second Best Issuer and sum the values in the columns Dirty value PC and Par Value LC. All the values are type string.
For example:
I'm a beginner with query and I'm looking for simple way to do this in C# with LINQ.
Thank You
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("IPC", typeof(int));
dt.Columns.Add("Dirty", typeof(int));
dt.Columns.Add("Second", typeof(string));
dt.Columns.Add("Par", typeof(int));
dt.Rows.Add(new object[] { 1, 5, "BB", 55 });
dt.Rows.Add(new object[] { 1, 4, "B", 30 });
dt.Rows.Add(new object[] { 2, 15, "AAA", 20 });
dt.Rows.Add(new object[] { 1, 10, "BB", 80 });
dt.Rows.Add(new object[] { 2, 20, "AA", 90 });
dt.Rows.Add(new object[] { 2, 30, "AAA", 50 });
dt.Rows.Add(new object[] { 1, 5, "B", 60 });
dt.Rows.Add(new object[] { 2, 15, "AA", 70 });
var groups = dt.AsEnumerable().GroupBy(x => new {ipc = x.Field<int>("IPC"), second = x.Field<string>("Second")}).ToList();
DataTable dtsum = dt.Clone();
foreach(var group in groups)
{
dtsum.Rows.Add(new object[] {group.Key.ipc, group.Sum(y => y.Field<int>("Dirty")), group.Key.second, group.Sum(y => y.Field<int>("Par"))});
}
}
}
}
In my system I have a table with participants weight history (ParticipantData):
ParticipantId Weight Date
1 86 2020-01-30
1 83 2020-02-03
2 98 2020-01-20
2 96 2020-01-26
3 75 2020-02-06
I need to get the sum of weights, but a participant must only count one time with their latest weight before or equal to a specific date.
Here's what I have so far:
DateTime dt = DateTime.Now;
DateTime? chartStartDate = new DateTime(Event.Event.StartDateTime.Value.Year, Event.Event.StartDateTime.Value.Month, Event.Event.StartDateTime.Value.Day);
DateTime? chartEndDate = dt < Event.Event.EndDateTime ? dt : Event.Event.EndDateTime;
bool chartLoop = true;
if (chartStartDate < dt) {
// Get all weights
var participantsWeightStats = await _context.ParticipantData.ToListAsync();
// Loop date with steps of 7
do {
// Get the sum of `participantsWeightStats` before or equal to the loop-date
// In the following I need to Distinct/GroupBy ParticipantId so every participant only counts with the latest weight
var chartData = participantsWeightStats.Where(x => x.Date <= chartStartDate).OrderByDescending(x => x.Date).ToList();
ViewData["PData_Values"] += chartData.Sum(x => x.Weight).ToString().Replace(".", "").Replace(",", ".") + ",";
ViewData["PData_Labels"] += "'" + chartStartDate.Value.ToString("d") + "',";
chartStartDate = chartStartDate.Value.AddDays(7);
if (chartStartDate > chartEndDate && chartLoop) {
chartStartDate = chartEndDate;
chartLoop = false;
}
} while (chartStartDate <= chartEndDate);
}
I've tried different approaches with GroupBy and Distinct but with no luck.
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ParticipantId", typeof(int));
dt.Columns.Add("Weight", typeof(int));
dt.Columns.Add("Date", typeof(DateTime));
dt.Rows.Add(new object[] {1, 86, DateTime.Parse("2020-01-30")});
dt.Rows.Add(new object[] {1, 83, DateTime.Parse("2020-02-03")});
dt.Rows.Add(new object[] {2, 98, DateTime.Parse("2020-01-20")});
dt.Rows.Add(new object[] {2, 96, DateTime.Parse("2020-01-26")});
dt.Rows.Add(new object[] {2, 75, DateTime.Parse("2020-02-06")});
DateTime endDate = DateTime.Parse("2020-01-31");
int sum = dt.AsEnumerable()
.Where(x => x.Field<DateTime>("Date") <= endDate)
.OrderByDescending(x => x.Field<DateTime>("Date"))
.GroupBy(x => x.Field<int>("ParticipantId"))
.Sum(x => x.First().Field<int>("Weight"));
}
}
}
I have a simple table in the following structure.
I want to write a LINQ expression to fetch only 5 records always. This 5 should be "Gold" if available. Otherwise add "Bronze" to make it 5. If it still not 5 then add "Silver" to the list. But total results returned should be 5. It should be good in terms of performance.
I tried basic linq but no luck. Any help is highly appreciated.
Class :
public class Option {
public int Id {get;set;
public string Name {get;set;}
public string Priority {get;set;}
}
dbContext.Options would create a connection to database table through ORM and we can apply linq expressions there.
Attempt : dbContext.Options.OrderByDescending(o => o.Priority).GroupBy(a => a.Priority)
this returns grouped result by priority. But i want to include the logic i needed inside this expression.
You want to assign a sort value to each string so that they are ordered. You can do this by assigning the integer 0 to Gold, 1 to Bronze, and 2 for Silver (other).
You then use Take to just get the first 5 records.
// ordered by gold, bronze, silver
var result = dbContext.Options
.OrderBy(o => o.Priority == "Gold" ? 0 : o.Priority == "Bronze" ? 1 : 2)
.Take(5)
.ToList();
It should be good in terms of performance.
Then you could consider using raw SQL to filter the records in the original query that is executed against the database, e.g.:
dbContext.Options.SqlQuery("SELECT TOP 5 * FROM [Option] ORDER BY CASE WHEN [Priority] = 'Gold' THEN 1 WHEN [Priority] = 'Bronze' THEN 2 WHEN [Priority] = 'Silver' THEN 3 ELSE 4 END").ToArray();
Maximal performance and LINQ seldom go hand in hand when it comes to querying databases.
Let Priority be an enum, orderby it and take 5.
class Option
{
public int Id { get; set; }
public string Name { get; set; }
public Priority Priority { get; set; }
}
enum Priority
{
Gold = 0,
Silver,
Bronze
}
static void Main(string[] args)
{
var list = new List<Option>()
{
new Option { Id = 1, Name = "Bob", Priority = Priority.Gold },
new Option { Id = 2, Name = "Rob", Priority = Priority.Gold },
new Option { Id = 2, Name = "David", Priority = Priority.Bronze },
new Option { Id = 2, Name = "Adam", Priority = Priority.Bronze },
new Option { Id = 2, Name = "Jack", Priority = Priority.Silver },
new Option { Id = 2, Name = "Josh", Priority = Priority.Silver },
new Option { Id = 2, Name = "Peter", Priority = Priority.Silver },
new Option { Id = 2, Name = "Max", Priority = Priority.Silver },
new Option { Id = 2, Name = "Steve", Priority = Priority.Silver },
};
var newList = list.OrderBy(l => l.Priority).Take(5);
}
List<Option> top5 = participants.OrderBy(part => {
switch(part.Priority) {
case "Gold": return 1;
case "Bronze": return 2;
case "Silver": return 3;
default: return 4;
}
}).Take(5).ToList();
If the list is shorter than 5, just order them, if that is needed.
See code below :
List<string> rank = new List<string>() { "Gold", "Bronze","Silver" };
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Priority", typeof(string));
dt.Rows.Add(new object[] { 9, "Steve", "Silver" });
dt.Rows.Add(new object[] { 8, "Max", "Silver" });
dt.Rows.Add(new object[] { 7, "Peter", "Silver" });
dt.Rows.Add(new object[] { 6, "Josh", "Silver" });
dt.Rows.Add(new object[] { 5, "Jack", "Bronze" });
dt.Rows.Add(new object[] { 4, "Adam", "Bronze" });
dt.Rows.Add(new object[] { 3, "David", "Gold" });
dt.Rows.Add(new object[] { 1, "Bob", "Gold" });
dt.Rows.Add(new object[] { 2, "Rob", "Gold" });
DataRow[] results = dt.AsEnumerable().OrderBy(x => rank.IndexOf(x.Field<string>("Priority"))).Take(5).ToArray();
I have data table having rows like
ID Name
2 A
4 B
3 C
5 D
1 E
List order = new List() { "1", "3", "2", "5", "4" }
--------------order by list-----------------
ID Name
1 E
3 C
2 A
5 D
4 B
can anyone help to implement this.. I am using DataTable in Winforms.
Another solution to the already given ones, would be to loop your order list and then sort your source list.
// source list
List<Foo> lSource = new List<Foo>() {
new Foo() { ID = 2, Name = "A" },
new Foo() { ID = 4, Name = "B" },
new Foo() { ID = 3, Name = "C" },
new Foo() { ID = 5, Name = "D" },
new Foo() { ID = 1, Name = "E" },
};
// order list
List<int> order = new List<int>() { 1, 3, 2, 5, 4 };
// loop order list and sort source list
order.ForEach(x =>
{
lSource = lSource.OrderBy(g => g.ID == x).ToList();
});
// set datasource
dataGridView1.DataSource = lSource;
I just added a class Foo containing an int ID and a string Name, because you didn't share your whole code.
I think you can join your order and your datatable with AsEnumerable method and on on part you can equalize both of them and select rows, then you can generate a DataTable from that query with CopyToDataTable method.
var dt = new DataTable();
var dc = new DataColumn() { ColumnName = "ID", DataType = typeof(string) };
dt.Columns.Add(dc);
dc = new DataColumn() { ColumnName = "Name", DataType = typeof(string) };
dt.Columns.Add(dc);
dt.Rows.Add(new object[] { "2", "A" });
dt.Rows.Add(new object[] { "4", "B" });
dt.Rows.Add(new object[] { "3", "C" });
dt.Rows.Add(new object[] { "5", "D" });
dt.Rows.Add(new object[] { "1", "E" });
List<string> order = new List<string>() { "1", "3", "2", "5", "4" };
var query = from item in order
join row in dt.AsEnumerable() on item equals row.Field<string>("ID")
select row;
var result = query.CopyToDataTable();
result will be;
I'm not sure this is the best way or not but this seems to fit with your case.
You can join both lists (the one with items and the one with sorted id's) and then select the items:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list = new List<Item>{
new Item { Id = 2, Text = "A" },
new Item { Id = 4, Text = "B" },
new Item { Id = 3, Text = "C" },
new Item { Id = 5, Text = "D" },
new Item { Id = 1, Text = "E" }
};
var sortorder = new List<int> { 1, 3, 2, 5, 4 };
var sortedlist = sortorder.Join(list, x => x, y => y.Id, (x,y) => y);
foreach(var item in sortedlist)
Console.WriteLine("{0} {1}", item.Id, item.Text);
}
}