using Microsoft.EntityFrameworkCore;
using Microsoft.Data.Sqlite;
using System.Collections.Generic;
public static void Main()
var res = Conteggio(Source.Turni,"Anno","Mese");
res = Conteggio(Source.Turni,"Qualifica","Mese");
res = Conteggio(Source.Turni,"Qualifica","Mese","Anno");
res = Conteggio(Source.Turni,"Cambio","Mese","Anno");
res = Conteggio(Source.Turni,"Cambio","Mese","Nome");
res = Conteggio(Source.Turni,"Nome","Qualifica","Mese","Anno","Cambio","Autorizzato");
public static List<Conteggio> Conteggio(List<Turno> source, params string[] Campi)
Console.WriteLine(string.Join(' ', Campi));
using (var db = new DBContext())
db.Turni.RemoveRange(db.Turni);
db.Turni.AddRange(source);
Dictionary<string, string> sqlParts = new Dictionary<string, string>();
sqlParts.Add("Mese", " strftime('%m',t.Inizio)#");
sqlParts.Add("Anno", " strftime('%Y',t.Inizio)#");
sqlParts.Add("Autorizzato", " CASE WHEN t.Autorizzato THEN ' Autorizzato ' ELSE ' Non autorizzato ' END#");
sqlParts.Add("Cambio", " CASE WHEN t.Cambio THEN CASE WHEN(t.Inizio = t.Fine) OR((t.Inizio IS NULL) AND(t.Fine IS NULL)) THEN ' Chiesto cambio ' ELSE ' Dato cambio ' END ELSE ' Nessun cambio ' END#");
sqlParts.Add("Nome", " t.Nome#");
sqlParts.Add("Qualifica", " t.Qualifica#");
var sqlFields = string.Concat(Campi.Select(s => sqlParts[s])).Replace("#",", ");
var sql = $" SELECT Id, {sqlFields}"
+ $" {string.Join(" || ' ' || ", Campi.Select(s => sqlParts[s])).Replace('#', ' ')} as Dato,"
+ $" Count(*) as Valore,"
+ $" SUM((julianday(t.Fine)-julianday(t.Inizio))*(24)) as Ore"
+ $" GROUP BY {sqlFields.Remove(sqlFields.Length - 2)}";
return db.Conteggi.FromSqlRaw(sql).ToList();
static void WriteResult(List<Conteggio> result)
result.ForEach(res=>Console.WriteLine($"Dato: {res.Dato}, Valore: {res.Valore}, Totale ore: {res.Ore}"));
public int Id { get; set; }
public string? Nome { get; set; }
public string? Qualifica { get; set; }
public DateTimeOffset? Inizio { get; set; }
public DateTimeOffset? Fine { get; set; }
public bool Cambio { get; set; }
public bool Autorizzato { get; set; }
public class DBContext : DbContext
static SqliteConnection _connection;
public DBContext(){Database.EnsureCreated();}
_connection = new SqliteConnection("DataSource=DbTest;mode=memory;cache=shared");
public DbSet<Turno> Turni { get; set; }
public DbSet<Conteggio> Conteggi { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)=>optionsBuilder.UseSqlite(_connection);
public int Id { get; set; }
public string? Dato { get; set; }
public int Valore { get; set; }
public double Ore { get; set; }
static Random rand = new Random();
static DateTimeOffset DataPartenza = DateTimeOffset.Now.Subtract(new TimeSpan(150, 0, 0, 0));
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static List<Turno> Turni { get; set; }
static Source(){Populate();}
public static void Populate(int NElemets=10)
Turni = new List<Turno>();
for (int i = 0; i < NElemets; i++)
turno.Autorizzato = Convert.ToBoolean(rand.Next(0, 2));
turno.Cambio = Convert.ToBoolean(rand.Next(0, 2));
turno.Inizio = DataPartenza.AddHours(rand.Next(3592));
turno.Fine = turno.Cambio ? rand.Next(0, 2) == 1 ? turno.Inizio : turno.Inizio?.AddHours(rand.Next(1, 8)) : turno.Inizio?.AddHours(rand.Next(1, 8));
turno.Nome = new string(Enumerable.Repeat(chars, rand.Next(1, 3)).Select(s => s[rand.Next(s.Length)]).ToArray());
turno.Qualifica = rand.Next(5).ToString();