Opinione: I trigger sono come un comportamento nascosto, a meno che non li cerchi, di solito non ti rendi conto che sono lì. Mi piace anche mantenere il DB più "stupido" possibile quando si utilizza EF, dal momento che sto usando EF quindi il mio team non avrà bisogno di mantenere il codice SQL.
Per la mia soluzione (mix di ASP.NET WebForms e MVC in C# con Business Logic in un altro progetto, che contiene anche il DataContext):
Recentemente ho avuto un problema simile, e anche se per la mia situazione è era più complesso (DatabaseFirst, quindi richiedeva un file TT personalizzato), la soluzione è quasi sempre la stessa.
ho creato un'interfaccia:
public interface ITrackableEntity
{
DateTime CreatedDateTime { get; set; }
int CreatedUserID { get; set; }
DateTime ModifiedDateTime { get; set; }
int ModifiedUserID { get; set; }
}
Poi ho appena implementato tale interfaccia su tutte le entità che avevo bisogno di (perché la mia soluzione era DatabaseFirst, ho aggiornato il file TT per verificare se il tavolo aveva quei quattro colonne, e se è così ha aggiunto l'interfaccia all'output).
UPDATE: ecco la mia modifiche al file TT, dove ho aggiornato il metodo EntityClassOpening()
:
public string EntityClassOpening(EntityType entity)
{
var trackableEntityPropNames = new string[] { "CreatedUserID", "CreatedDateTime", "ModifiedUserID", "ModifiedDateTime" };
var propNames = entity.Properties.Select(p => p.Name);
var isTrackable = trackableEntityPropNames.All(s => propNames.Contains(s));
var inherits = new List<string>();
if (!String.IsNullOrEmpty(_typeMapper.GetTypeName(entity.BaseType)))
{
inherits.Add(_typeMapper.GetTypeName(entity.BaseType));
}
if (isTrackable)
{
inherits.Add("ITrackableEntity");
}
return string.Format(
CultureInfo.InvariantCulture,
"{0} {1}partial class {2}{3}",
Accessibility.ForType(entity),
_code.SpaceAfter(_code.AbstractOption(entity)),
_code.Escape(entity),
_code.StringBefore(" : ", String.Join(", ", inherits)));
}
L'unica cosa rimasta era quella di aggiungere il seguente alla mia parziale classe DataContext:
public override int SaveChanges()
{
// fix trackable entities
var trackables = ChangeTracker.Entries<ITrackableEntity>();
if (trackables != null)
{
// added
foreach (var item in trackables.Where(t => t.State == EntityState.Added))
{
item.Entity.CreatedDateTime = System.DateTime.Now;
item.Entity.CreatedUserID = _userID;
item.Entity.ModifiedDateTime = System.DateTime.Now;
item.Entity.ModifiedUserID = _userID;
}
// modified
foreach (var item in trackables.Where(t => t.State == EntityState.Modified))
{
item.Entity.ModifiedDateTime = System.DateTime.Now;
item.Entity.ModifiedUserID = _userID;
}
}
return base.SaveChanges();
}
Nota che ho salvato l'ID utente corrente in un campo privato della classe DataContext ogni volta che l'ho creato.
questa è una risposta ben dettagliata, grazie Tim. Sono convinto a modo tuo ed è bene mantenere questa logica nel livello dell'applicazione. Pensi che sia possibile o utile per il team EF aggiungere vincoli predefiniti e attivare il supporto in DataAnnotation o FluentAPI? – anIBMer
Vorrei dare il benvenuto al team EF aggiungendo che renderebbe le cose più semplici con regole semplici. Detto questo, ci sono così spesso eccezioni alle regole, quindi sapere come prendere il pieno controllo del processo è un'abilità preziosa da apprendere. –
Esattamente quali aggiornamenti hai apportato al file TT? – Fergal