Sto usando EF Core 2.0 con SQLite e voglio ridurre la dimensione del mio database senza perdere il valore datetime umano leggibile nella mia colonna della tabella. Attualmente il contesto dati archivia l'oggetto CLR DateTime completo come una stringa come "2018-03-10 16: 18: 17.1013863", ma nel mio caso "2018-03-10 16:18:17" sarebbe sufficiente. Cosa devo fare?
I secondi frazionari non vengono memorizzati se sono zero. Puoi tranquillamente rimuoverli dai dati esistenti. Aggiorna la tua applicazione per non specificarli. Puoi farlo con impazienza (quando imposti i valori DateTime
sulle tue entità) o pigramente durante SaveChanges
.
public override int SaveChanges()
{
var dateTimeProperties =
from e in ChangeTracker.Entries()
where e.State == EntityState.Added
|| e.State == EntityState.Modified
from p in e.Properties
where p.CurrentValue is DateTime
select p;
foreach (var property in dateTimeProperties)
{
// Strip millisecond
var value = (DateTime)property.CurrentValue;
property.CurrentValue = new DateTime(
value.Year,
value.Month,
value.Day,
value.Hour,
value.Minute,
value.Second);
}
return base.SaveChanges();
}
Se vuoi davvero radere ancora più dimensioni, puoi aggiungere una conversione personalizzata a ogni colonna per ridurre le dimensioni, in questo modo:
protected override void OnModelCreating(ModelBuilder constructor) =>
constructor.Entity<YourEntity>().Property(c => c.DatePropertyOfYourEntity)
.HasConversion(f => f.ATextoYYMMDD(), s => s.AFechaYYMMDD());
Ho usato i seguenti metodi di estensione per una conversione molto veloce tra la data e il formato stringa YYMMDD
:
public static string ATextoYYMMDD(this DateTime fechaHora) {
var chars = new char[6];
var valor = fechaHora.Year % 100;
chars[0] = (char)(valor / 10 + '0');
chars[1] = (char)(valor % 10 + '0');
valor = fechaHora.Month;
chars[2] = (char)(valor / 10 + '0');
chars[3] = (char)(valor % 10 + '0');
valor = fechaHora.Day;
chars[4] = (char)(valor / 10 + '0');
chars[5] = (char)(valor % 10 + '0');
return new string(chars);
}
public static DateTime AFechaYYMMDD(this string s)
=> new DateTime((s[0] - '0') * 10 + s[1] - '0' + 2000,
(s[2] - '0') * 10 + s[3] - '0', (s[4] - '0') * 10 + s[5] - '0');
Se vuoi andare e applicarlo a più entità che implementano un'interfaccia puoi fare:
var convertidor = new ValueConverter<DateTime, string>
(f => f.ATextoYYMMDD(), s => s.AFechaYYMMDD());
foreach (var tipoEntidad in constructor.Model
.GetEntityTypes().Where(t => typeof(IYourInterface).IsAssignableFrom(t.ClrType.BaseType))) {
constructor.Entity(tipoEntidad.Name)
.Property("YourPropertyName").HasConversion(convertidor);
}
Oppure puoi applicarlo anche a tutte le proprietà della data, vedi HasConversion EF CORE 2.1 su tutte le proprietà del tipo datetime