I have table with these columns:
id int, name string, startDate DateTime, endDate DateTime
I want to get from DB SUM of HOURS between these dates for all records.
I use IQueryable, but I don't know how correctly form the query..
public int GetSumOfHours(int? assignedProjectId)
{
var query = GetAll(); //GetAll() returns IQueryable<T>,
if (assignedProjectId.HasValue)
{
query = query.Where(solution => solution.AssignedProject.Id == assignedProjectId.Value);
}
// Get sum of hours ----> query = query...??
}
Thanks for HELP !
Try something like below. Get seconds and then sum the seconds.
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 query = new DataTable();
query.Columns.Add("id", typeof(int));
query.Columns.Add("name", typeof(string));
query.Columns.Add("startDate", typeof(DateTime));
query.Columns.Add("endDate", typeof(DateTime));
query.Rows.Add(new object[] { 1, "John", DateTime.Parse("1/1/1 0:0:12"), DateTime.Parse("1/1/1 0:1:12") });
query.Rows.Add(new object[] { 1, "John", DateTime.Parse("1/1/1 0:3:12"), DateTime.Parse("1/1/1 0:5:12") });
query.Rows.Add(new object[] { 2, "Bob", DateTime.Parse("1/1/1 0:0:12"), DateTime.Parse("1/1/1 0:1:12") });
query.Rows.Add(new object[] { 2, "Bob", DateTime.Parse("1/1/1 0:0:12"), DateTime.Parse("1/1/1 0:1:12") });
var totalSeconds = query.AsEnumerable()
.Where(x => x.Field<int>("id") == 1)
.Select(x => (x.Field<DateTime>("endDate") - x.Field<DateTime>("startDate")).TotalSeconds).Sum();
}
}
}
You can use some math and the Sum() method:
public class hours
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
...
List<hours> allHrs = new List<hours>{
new hours{Start = DateTime.Now.AddHours(-3.2), End = DateTime.Now.AddHours(-2)},
new hours{Start = DateTime.Now.AddHours(-3.9), End = DateTime.Now.AddHours(-2.03)},
new hours{Start = DateTime.Now.AddHours(-3.8), End = DateTime.Now.AddHours(-2.9)}
};
//Project a new collection with the math done for number of minutes in each row
var mins = from h in allHrs
select new {nbrMinutes = (h.End - h.Start).Minutes};
//Sum all rows, divide by 60 to get hours
Double total = mins.Sum (s => s.nbrMinutes / 60.0 );
Console.WriteLine(total);
You could modify CrowCoder's example to sum the hours directly using TimeSpan and methods Subtract and TotalHours:
{
DateTime d = DateTime.Today;
List<hours> exampleHours = new List<hours>{
new hours{Start = d.AddHours(-3.2), End = d.AddHours(-2)},
new hours{Start = d.AddHours(-3.9), End = d.AddHours(-2.03)},
new hours{Start = d.AddHours(-3.8), End = d.AddHours(-2.9)}
};
double totalHours =
(from h in exampleHours
select new {allHours = (h.End.Subtract(h.Start).TotalHours)})
.Sum(t => t.allHours);
Console.WriteLine(totalHours.ToString());
}
Related
My current DataGridView looks like this:
I'd like to achieve that each (column) "Fachanwendung" is grouping the data by displaying it as a Header. I've tried it with the DataGridViewGrouper like here: https://10tec.com/articles/datagridview-grouping-two-recipes.aspx
https://www.codeproject.com/Tips/995958/DataGridViewGrouper
Unfortunately, my DataSource and DataMembers are either null or "". Therefore I can't call it like this:
DataGridViewGrouper grouper = new DataGridViewGrouper(dataGridView);
grouper.SetGroupOn("Fachanwendung");
//grouper.SetGroupOn(this.dataGridView.Columns["fachanwendung"]);
Is there any other way to display (at least a text) over a specific row?
I created a DataTable which you can use as the DatSource of the DGV. See code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication98
{
class Program
{
static void Main(string[] args)
{
List<Element> elements = new List<Element>() {
new Element() { Fachanwendung = "archiMap", Elementtyp = "Herstellerproduktversion", Elementname = "Java SE JRE 8", Date = DateTime.Parse("1/1/2017"), Quantity = 10},
new Element() { Fachanwendung = "archiMap", Elementtyp = "Herstellerproduktversion", Elementname = "Microsoft Window Server 2012 Standard", Date = DateTime.Parse("3/1/2017"), Quantity = 12},
new Element() { Fachanwendung = "Event Management System", Elementtyp = "Herstellerproduktversion", Elementname = "Apache Toimcat 8.0", Date = DateTime.Parse("6/1/2018"), Quantity = 5},
new Element() { Fachanwendung = "Event Management System", Elementtyp = "Herstellerproduktversion", Elementname = "Oracle Java JDK 7", Date = DateTime.Parse("12/1/2018"), Quantity = 5},
new Element() { Fachanwendung = "Event Management System", Elementtyp = "Herstellerproduktversion", Elementname = "Oracle Java JDK 8", Date = DateTime.Parse("1/1/2019"), Quantity = 5}
};
Dictionary<string, List<Element>> dict = elements.GroupBy(x => x.Fachanwendung, y => y)
.ToDictionary(x => x.Key, y => y.ToList());
DataTable dt = new DataTable();
dt.Columns.Add("Fachanwendung", typeof(string));
dt.Columns.Add("Elementtyp", typeof(string));
dt.Columns.Add("Elementname", typeof(string));
//add quarters
DateTime minDate = dict.SelectMany(x => x.Value.Select(y => y.Date)).Min(x => x.Date);
DateTime maxDate = dict.SelectMany(x => x.Value.Select(y => y.Date)).Max(x => x.Date);
DateTime startQuarter = new DateTime(minDate.Year, ((minDate.Month - 1) % 3) + 1, 1);
DateTime endQuarter = new DateTime(maxDate.Year, ((maxDate.Month - 1) % 3) + 1, 1);
for (DateTime date = startQuarter; date <= endQuarter; date = date.AddMonths(3))
{
dt.Columns.Add(date.Year.ToString() + " Q" + (((date.Month - 1)/ 3) + 1).ToString(), typeof(int));
}
foreach (KeyValuePair<string, List<Element>> rows in dict)
{
var groups = dict[rows.Key].GroupBy(x => new { Elementtyp = x.Elementtyp, Elementname = x.Elementname, Date = new DateTime(x.Date.Year, ((x.Date.Month - 1) % 3) + 1, 1) }).ToList();
foreach (var group in groups)
{
DataRow newRow = dt.Rows.Add();
newRow["Fachanwendung"] = rows.Key;
newRow["Elementtyp"] = group.Key.Elementtyp;
newRow["Elementname"] = group.Key.Elementname;
string quarter = group.Key.Date.Year.ToString() + " Q" + (((group.Key.Date.Month - 1) / 3) + 1).ToString();
int total = group.Sum(x => x.Quantity);
newRow[quarter] = total;
}
}
}
}
public class Element
{
public string Fachanwendung { get; set; }
public string Elementtyp { get; set; }
public string Elementname { get; set; }
public DateTime Date { get; set; }
public int Quantity { get; set; }
}
}
I got your requirement now basically you want to have a block for each group in the data grid view. This can be resolved using Nested grid view. Here is very good link which you can use https://www.codeproject.com/Articles/848637/Nested-DataGridView-in-windows-forms-csharp
Also if you don't want expand collapse functionality you can easily remove that. Let me know if you need help with that.
I have a list of MyClass:
class MyClass
{
public DateTime? DueDate;
public string Desc;
public Decimal Amount;
}
var sample = new List<MyClass>();
This is how sample data looks like :
DueDate Desc Amount
06-29-2015 ABC 100
06-29-2015 DEF 200
01-15-2015 ABC 100
01-15-2015 DEF 200
Output I want in this format
DueDate Desc Amount
06-29-2015 ABC 100
DEF 200
01-15-2015 ABC 100
DEF 200
So basically I would like to remove duplicate DueDate values but keeping its adjacent Desc & Amount field values
I tried this but it will remove values from adjacent column as well :
var test = sample.GroupBy(d => d.DueDate).Select(a => a.First()).ToList();
Any suggestions?
Here's how to "remove" (set to null) duplicate, adjacent DueDates from the sample list:
sample.GroupBy(d => d.DueDate).ToList()
.ForEach(g => g.Skip(1).ToList().ForEach(o => o.DueDate = null));
This is done by Group-ing by DueDate, and for each group, Skip-ing the first element, setting the remainder of the elements in the group DueDates to null.
Output with format:
Console.WriteLine("DueDate Desc Amount");
foreach (var item in sample)
{
var dateString = item.DueDate != null
? item.DueDate.Value.ToString("MM-dd-yyyy")
: string.Empty;
Console.WriteLine(dateString.PadRight(12) + item.Desc + " " + item.Amount);
}
Result:
DueDate Desc Amount
06-29-2015 ABC 100
DEF 200
01-15-2015 ABC 100
DEF 200
var finalData = data
.GroupBy(d=>d.DueDate)
.Select(g=>
new {
DueDate = g.Key,
Values = g.Select(d2=>new{d2.Desc, d2.Amount})})
The Final Structure would be
finalDate = [
{
DueDate:'06-29-1015',
Values:[{Desc:"ABC", Amount:100}, {Desc:"DEF", Amount:200}]
},
{...}
]
EDIT:-
var finalData = data
.GroupBy(d=>d.DueDate)
.Select(g=>
new {
DueDate = g.Key,
Values = g.Select(d2=>d2)
})
.ToDictionary(o=>o.DueDate, o=>o.Values)
What you want is a pivot table. this is how it is done :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Load();
myClass.CreatePivotTable();
}
}
class MyClass
{
public static List<MyClass> samples = new List<MyClass>();
public DateTime dueDate { get; set; }
public string desc { get; set; }
public Decimal amount { get; set; }
public static DataTable dt = new DataTable();
public void Load()
{
samples = new List<MyClass>() {
new MyClass() { dueDate = DateTime.Parse("06-29-2015"), desc = "ABC", amount = 100},
new MyClass() { dueDate = DateTime.Parse("06-29-2015"), desc = "DEF", amount = 200},
new MyClass() { dueDate = DateTime.Parse("01-15-2015"), desc = "ABC", amount = 100},
new MyClass() { dueDate = DateTime.Parse("01-15-2015"), desc = "DEF", amount = 100}
};
}
public void CreatePivotTable()
{
string[] uniqueDescription = samples.Select(x => x.desc).Distinct().ToArray();
dt.Columns.Add("Due Date", typeof(DateTime));
foreach (string desc in uniqueDescription)
{
dt.Columns.Add(desc, typeof(decimal));
}
var groups = samples.GroupBy(x => x.dueDate);
foreach(var group in groups)
{
DataRow newRow = dt.Rows.Add();
newRow["Due Date"] = group.Key;
foreach (string col in uniqueDescription)
{
newRow[col] = group.Where(x => x.desc == col).Sum(x => x.amount);
}
}
}
}
}
I'd simply prefer that you loop through your records after you got them in the correct order. Just start with an empty variable and keep the last date in it. If the next value is the same, just don't plot it out. If you find another date value the next iteration, plot it and overwrite your variable for further iterations.
Yeah I know, Linq and Lambdas are cool and stuff (and I love them too) but in this case it seems to be appropriate to me.
var last = DateTime.MinValue;
foreach (var f in sample.OrderBy(x => x.DueDate))
{
if (f.DueDate.Equals(last))
Console.WriteLine("{0}\t{1}\t{2}", "SKIP DATE", f.Desc, f.Amount);
else
{
Console.WriteLine("{0}\t{1}\t{2}", f.DueDate.ToShortDateString(), f.Desc, f.Amount);
last = f.DueDate;
}
}
Based on your latest comments I have edited my answer.
As I am understanding, your requirements are:
Group by DueDate, and only allow the first of the group to have a
DueDate.
The results have to be the same structure.
If you want to remove the DueDate property from all i>0 items in a group then you need to make your property nullable: public DateTime? DueDate;. This way you can assign the value of null to subsequent items in the group.
//New list to hold our new items
var outputList = new List<MyClass>();
//Groups all the items together by DueDate
foreach(var grouping in samples.GroupBy(d => d.DueDate))
{
//Iterates through all items in a group (selecting the index as well)
foreach(var item in grouping.Select((Value, Index) => new { Value, Index }))
{
//If this is any item after the first one, we remove the due date
if(item.Index > 0)
{
item.Value.DueDate = null;
}
outputList.Add(item.Value);
}
}
Fiddle here.
I have a stored procedure that looks like this:
SELECT UrlId, TypeId, DomainId, Url, d.OrgId AS orgId
FROM SystemUrls
JOIN Domaindata d ON d.Id = DomainId
It gives me this result:
in the code this looks like:
What I would like:
is to group this result on the domainId
so that I get two rows.
I have this class:
public class TestModel
{
public long DomainId { get; set; }
public List<SystemUrl> Urls { get; set; }
}
I am trying to get a resul like :
DomainId 79 Urls.count() = 2
DomainId 81 Urls.COunt = 2
My attempt:
var t =
(from u in urls
select
new TestModel
{
DomainId = u.DomainId,
Urls = new List<SystemUrl> {new SystemUrl {Url = u.Url}}
}).GroupBy(v => v.DomainId).ToList();
the problem is that I seem to get the domainId right but none of the other data seems to follow:
How can I solve this?
var t = urls.GroupBy(u => u.DomainId)
.Select(g => new TestModel{
DomainId = g.Key,
Urls = g.Select(u => new SystemUrl {Url = u.Url}).ToList()
})
.ToList();
Here is how you can do it:
var t = urls.GroupBy(v => v.DomainId).Select(g => new TestModel
{
DomainId = g.Key,
Urls = g.Select(u => new SystemUrl {Url = u.Url}).ToList()
}).ToList();
Put DataAdapter reults into a datatable . Then use following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
namespace ConsoleApplication49
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Urld", typeof(int));
dt.Columns.Add("Typeid", typeof(int));
dt.Columns.Add("DomainId", typeof(int));
dt.Rows.Add(new object[] { 13, 1, 79 });
dt.Rows.Add(new object[] { 14, 2, 79 });
dt.Rows.Add(new object[] { 15, 2, 81 });
dt.Rows.Add(new object[] { 16, 1, 81 });
var results = dt.AsEnumerable()
.GroupBy(x => x.Field<int>("DomainID"))
.ToDictionary(x => x.Key, y => y.Count());
}
}
}
I have a collection of Orders which are pulled from EF. Each Order has an order date:
public class Order {
public DateTime Date { get; set; }
public int Id { get; set; }
}
I want to be able to run a query to return the number of orders for each day in a certain date range. The query method should look something like:
public class ICollection<OrderDateSummary> GetOrderTotalsForDateRange(DateTime startDate, DateTime endDate) {
var orderDateSummary = Set.SelectMany(u => u.Orders) // ..... grouping/totalling here?!
return orderDateSummary;
}
For info, Set is actually part of a repository which returns a User aggregate root, so the type of Set is DbSet<User> The bit I am stuck on is grouping and totalling the Orders queryable from the SelectMany method.
The OrderDateSummary class looks like:
public OrderDateSummary {
DateTime Date { get; set; }
int Total { get; set; }
}
So, the output for a start date of 01/01/2016 and an end date of 03/01/2016 would look something like:
Date Total
===================
01/01/2016 10
02/01/2016 2
03/01/2016 0
04/01/2016 12
As I can see you need to generate all dates in range from start to end. Then calculate total number of orders on each date.
DateTime start = new DateTime(2016, 1, 1);
DateTime end = new DateTime(2016, 1, 4);
Enumerable
.Range(0, 1 + (end - start).Days)
.Select(x => start.AddDays(x))
.GroupJoin(Set.SelectMany(u => u.Orders),
dt => dt, o => o.Date.Date,
(dt, orders) => new OrderDateSummary { Date = dt, Total = orders.Count() })
.ToList();
Check out working example on Ideone.
var startDate = new DateTime (2016, 1, 1);
var endDate = new DateTime (2016, 1, 4);
Set.SelectMany(u => u.Orders).
Where (order => startDate <= order.Date && order.Date <= endDate) // If filter needed
GroupBy (order => order.Date, (date, values) =>
new OrderDateSummary () {
Date = date,
Total = values.Count ()
}).
OrderBy (summary => summary.Date).
ToList ();
Just you should mark your OrderDateSummary with class or struct and make those properties public or add constructor.
And you have a date 04/01/2016 in expected result, so, I guess, your end time is 4th and not 3th.
Try code below which is linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication82
{
class Program
{
static void Main(string[] args)
{
List<OrderDateSummary> orderSummary = null;
DataTable dt = new DataTable();
dt.Columns.Add("id", typeof(int));
dt.Columns.Add("date", typeof(DateTime));
dt.Columns.Add("amount", typeof(decimal));
dt.Rows.Add(new object[] { 1, DateTime.Parse("1/1/16"), 1.00 });
dt.Rows.Add(new object[] { 2, DateTime.Parse("1/1/16"), 2.00 });
dt.Rows.Add(new object[] { 3, DateTime.Parse("1/2/16"), 3.00 });
dt.Rows.Add(new object[] { 4, DateTime.Parse("1/2/16"), 4.00 });
dt.Rows.Add(new object[] { 5, DateTime.Parse("1/2/16"), 5.00 });
dt.Rows.Add(new object[] { 6, DateTime.Parse("1/3/16"), 6.00 });
dt.Rows.Add(new object[] { 7, DateTime.Parse("1/3/16"), 7.00 });
orderSummary = dt.AsEnumerable()
.GroupBy(x => x.Field<DateTime>("date"))
.Select(x => new OrderDateSummary() { Date = x.Key, Total = x.Count() })
.ToList();
}
}
public class OrderDateSummary {
public DateTime Date { get; set; }
public int Total { get; set; }
}
}
how about
List<OrderDateSummary> Result = OrderList
.Where(x => x.Date >= startDate && x.Date <= endDate)
.GroupBy(x => x.Date)
.Select(z => new OrderDateSummary(){
Date = z.Key,
Total = z.Count()
}).OrderBy(d=> d.Date).ToList();
I have a LINQ query something like below:
var results=from p in inputTable.AsEnumerable()
where inputParameter.Contains(p.Field<String>(inputField))&&
p.Field<string>(CurrencyCode)==currencyCode
group p by new
{
p[CurrencyCode],
} into groupedTable
select new
{
Amount = groupedTable.Sum(r => r.Field<System.Decimal>(amountField))
};
if (results.Count() > 0)
{
retVal = results.ElementAt(0).Amount;
}
My inputParameter is basically a List<string> which will have values like {October, November, December}.
The inputField is November.
My thought is that since the where condition has a Contains method it will just filter rows by November, since inputField is November.
I basically need to pass all the elements of the list, i.e. October, November and December and then get records filtered by these months.
I tried to use where-in stuff of LINQ but was not successful.
Experts please help to crack this question.
Any help/pointer will be highly appreciable.
EDIT:
Let me try to make this question very simple.
My List<string> inputParameter can contain variable strings, like {October, November, December} or {January, February, March, April} and so on.
I need my query to pass in all these values and filter the records accordingly.
The simplified query which I tried is follows:
var results=from p in inputTable.AsEnumerable()
where p.Field<string>(FiscalMonth)==inputParameter[0] ||
p.Field<string>(FiscalMonth)==inputParameter[1] ||
p.Field<string>(FiscalMonth)==inputParameter[2]
select new
{
p.Amount
};
In the above instance I have basically hardcoded the individual elements of the List inputParameter, but my list will be variable at times. i.e it may hold 3 items, 4 items, or even 12 items.
How to mould the above query to avoid individual hard-coding?
Regards
Anurag
Responding to your edit, it should be :
var results = from p in inputTable.AsEnumerable()
where inputParameter.Contains(p.Field<string>(FiscalMonth))
select new
{
p.Amount
};
This is a working console example that demonstrate query with Contains :
//create datatable with column FiscalMonth
var table = new DataTable();
table.Columns.Add("FiscalMonth");
//add two rows, January and October
var row1 = table.NewRow();
row1["FiscalMonth"] = "January";
var row2 = table.NewRow();
row2["FiscalMonth"] = "October";
table.Rows.Add(row1);
table.Rows.Add(row2);
//query from data table where FiscalMonth in (October, November, December)
var inputParameter = new List<string> {"October", "November", "December"};
var result = from r in table.AsEnumerable()
where inputParameter.Contains(r.Field<string>("FiscalMonth"))
select r.Field<string>("FiscalMonth");
//the result will be only one row, which is October. January is successfully filtered out
foreach (var r in result)
{
Console.WriteLine(r);
}
Do not really understand exactly what you are looking for, since you are stating that you want to query on only Month and your code is querying on month and currency code. but looks like you are returning the sum of the Amount. So he is a first stab at what you want to do.
class MonthCurrency
{
public string Month { get; set; }
public int CurrencyCode { get; set; }
public decimal Amount { get; set; }
}
static List<MonthCurrency> inputTable = null;
static void Main(string[] args){
inputTable = new List<MonthCurrency>()
{ new MonthCurrency() { Month = "October", CurrencyCode= 1, Amount = 1},
new MonthCurrency() { Month = "October", CurrencyCode= 1, Amount = 2},
new MonthCurrency() { Month = "November", CurrencyCode= 2, Amount = 1},
new MonthCurrency() { Month = "November", CurrencyCode= 2, Amount = 2},
new MonthCurrency() { Month = "December", CurrencyCode= 3, Amount = 1},
new MonthCurrency() { Month = "December", CurrencyCode= 3, Amount = 2},
};
var result = GetCurrencyCode("November");
}
static public decimal GetCurrencyCode(string inputParameter)
{
decimal retVal = 0.0M;
var results = from p in inputTable.AsEnumerable()
where p.Month == inputParameter
group p by new
{
p.CurrencyCode,
} into groupedTable
select new MonthCurrency
{
Amount = groupedTable.Sum(r => r.Amount)
};
if (results.Count() > 0)
{
retVal = results.ElementAt(0).Amount;
}
return retVal;
}
Hopefully this will help you out