Architecture générique et héritage
Bonjour,
Je cherche à faire un supergénéric...
Du code parlant plus facilement, GO :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
// Eléments de structure
public abstract class Identifier
{
// Identifiant dans la base de données
public int ID { get; set; }
}
public abstract partial class NNLinkHistory<TIdentifierA, TIdentifierB> : IHistory
where IdentifierA : Identifier
where IdentifierB : Identifier
{
// Identifiant de la première entité
public int Identifier1ID { get; set; }
// Lien de navigation vers la première entité
public TIdentifierA Identifier1 { get; set; }
// Identifiant de la seconde entité
public int Identifier2ID { get; set; }
// Lien de navigation vers la seconde entité
Public TIdentifierB Identifier2 { get; set; }
// Date d'association (Interface IHistory)
public DateTime AssociationDate { get; set; } = DateTime.UtcNow;
// Date de dissociation (Interface IHistory)
public DateTime? DissociationDate { get; set; }
}
// Objets utiles
public class Object1 : Identifier
{
// V1
public ICollection<O1O2H> Object2sV1 { get; set; } = new HashSet<O1O2H>();
// V2
public MyCollection<O1O2H> Object2sV2 { get; set; } = new MyCollection<O1O2H>();
}
public class Object2 : Identifier
{
// V1
public ICollection<O1O2H> Object1sV1 { get; set; } = new HashSet<O1O2H>();
// V2
public MyCollection<O1O2H> Object1s { get; set; } = new MyCollection<O1O2H>();
}
public class O1O2H : NNLinkHistory<Object1, Object2>
{
public int OtherProperty{ get; set; }
} |
Ceux qui utilise un ORM reconnaitront un lien 0,N---0,N entre 2 tables. D'ailleurs tant que j'y suis, je précise que j'utilise EFCore 3.1.17 et que je ne puis monter sur la version 5 car le framework utilisé est le standard 4.8 incompatible... no comment :weird:
A cela, j'ai ajouté une méthode d'extension pour aller chercher la relation active
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
public static TEntity GetActive<TEntity>(this ICollection<TEntity> histories, BaseDbContext ctx)
where TEntity : class, IHistory
{
public NNLinkHistory<TIdentifierA, TIdentifierB> GetActive(DbContext ctx, bool isForceToReload = false)
{
// Si l'historique n'est pas null
if (this.Count() > 0 || !isForceToReload)
// Renvoyer l'historique
return this.First();
// Récupérer la propriété à utiliser par son type
var property = ctx.GetType()
.GetProperties()
.FirstOrDefault(o => o.PropertyType == typeof(DbSet<NNLinkHistory<TIdentifierA, TIdentifierB>>));
// Si la propriété n'a pas été trouvée
if (property == null)
// Générer une exception
throw new InvalidCastException();
var queryable = (IQueryable<NNLinkHistory<TIdentifierA, TIdentifierB>>)property.GetValue(ctx);
// Mettre à jour l'historique
Clear();
if (query.Count() > 0)
AddRange(query.ToList());
// Renvoyer l'historique
return this.OrderByDescending(o => o.AssociationDate).FirstOrDefault();
} |
Ca fonctionne impeccable mais j'aimerais pouvoir faire un objet à part entière pour pouvoir hériter de cet objet afin de définir une fonction GetActive légèrement différente pour une classe particulière :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
public class MyCollection<TNNLinkHistory> : List<TNNLinkHistory>
where TNNLinkHistory : NNLinkHistory<TIdentifierA, TIdentifierB> // Là déjà l'IDE râle car il ne connait pas TIdentifierA et TIdentifierB
{
public NNLinkHistory<TIdentifierA, TIdentifierB> GetActive(DbContext ctx, bool isForceToReload = false)
{
// Si l'historique n'est pas null
if (this.Count() > 0 || !isForceToReload)
// Renvoyer l'historique
return this.First();
// Récupérer la propriété à utiliser par son type
var property = ctx.GetType()
.GetProperties()
.FirstOrDefault(o => o.PropertyType == typeof(DbSet<NNLinkHistory<TIdentifierA, TIdentifierB>>));
// Si la propriété n'a pas été trouvée
if (property == null)
// Générer une exception
throw new InvalidCastException();
var queryable = (IQueryable<NNLinkHistory<TIdentifierA, TIdentifierB>>)property.GetValue(ctx);
// Mettre à jour l'historique
Clear();
if (query.Count() > 0)
AddRange(query.ToList());
// Renvoyer l'historique
return this.OrderByDescending(o => o.AssociationDate).FirstOrDefault();
}
} |
Mais là ça coince :aie:
Bien évidemment, il n'y a pas que la fonction GetActive, il y a entre autre SetActive (qui s'appuie sur GetActive) mais seule celle-ci sera différente (d'où l'intérêt de l'héritage).
Auriez-vous une idée ? :help: