J'ai une base de données contenant des composants avec environ 20 propriétés. Pour savoir si une mise à jour est nécessaire, je veux vérifier si toutes les propriétés des deux objets, à l'exception de DateCreated et Id, correspondent. Si tout ne correspond à aucune mise à jour, sinon, mettez à jour la base de données.
Component comp_InApp = new Component() { Id = null, Description = "Commponent", Price = 100, DateCreated = "2019-01-30", // Twenty more prop }; Component comp_InDb = new Component() { Id = 1, Description = "Component", Price = 100, DateCreated = "2019-01-01", // Twenty more prop }; // Check if all properties match, except DateCreated and Id. if (comp_InApp.Description == comp_InDb.Description && comp_InApp.Price == comp_InDb.Price // Twenty more prop ) { // Everything up to date. } else { // Update db. }
Cela fonctionne, mais ce n'est pas une manière très propre avec 20 propriétés. Existe-t-il une meilleure façon d'obtenir le même résultat d'une manière plus propre?
4 Réponses :
J'utilise DeepEqual lorsque je ne veux pas / n'ai pas le temps d'écrire moi-même méthodes Equals
et GetHashCode
.
Vous pouvez l'installer simplement à partir de NuGet avec:
if (comp_InApp.IsDeepEqual(comp_InDb)) { // Everything up to date. } else { // Update db. }
et l'utiliser comme:
Install-Package DeepEqual
Mais gardez à l'esprit que cela ne fonctionnera que pour votre cas lorsque vous souhaitez comparer explicitement des objets, mais pas pour le cas où vous souhaitez supprimer un formulaire objet une List
ou des cas comme celui-ci, lorsque Equals
et GetHashCode
sont appelés.
D'une manière, créez une classe qui implémente IEqualityComparer
pour encapsuler cette logique et pour éviter que vous ayez modifié la classe Comparer
elle-même (si vous ne veulent cette logique Equals
à tout moment). Ensuite, vous pouvez l'utiliser pour un simple Equals
de deux instances de Component
et même pour tout Méthodes LINQ qui l'accepte comme argument supplémentaire.
IEnumerable<Component> missingInDb = inAppList.Except( inDbList, comparer );
Votre cas d'utilisation simple:
var comparer = new ComponentComparer(); bool equal = comparer.Equals(comp_InApp, comp_InDb);
Cela fonctionne aussi si vous avez deux collections et que vous voulez connaître la différence, par exemple:
class ComponentComparer : IEqualityComparer<Component> { public bool Equals(Component x, Component y) { if (object.ReferenceEquals(x, y)) return true; if (x == null || y == null) return false; return x.Price == y.Price && x.Description == y.Description; } public int GetHashCode(Component obj) { unchecked { int hash = 17; hash = hash * 23 + obj.Price.GetHashCode(); hash = hash * 23 + obj.Description?.GetHashCode() ?? 0; // ... return hash; } } }
Voici une solution avec Reflection:
static bool AreTwoEqual(Component inApp, Component inDb) { string[] propertiesToExclude = new string[] { "DateCreated", "Id" }; PropertyInfo[] propertyInfos = typeof(Component).GetProperties() .Where(x => !propertiesToExclude.Contains(x.Name)) .ToArray(); foreach (PropertyInfo propertyInfo in propertyInfos) { bool areSame = inApp.GetType().GetProperty(propertyInfo.Name).GetValue(inApp, null).Equals(inDb.GetType().GetProperty(propertyInfo.Name).GetValue(inDb, null)); if (!areSame) { return false; } } return true; }
Vous pouvez utiliser une réflexion mais cela peut ralentir votre application. Une autre façon de créer ce comparateur est de le générer avec des expressions Linq. Essayez ce code:
var comparator = CreateAreEqualExpression<Component>( c => c.Id, c => c.DateCreated) .Compile();
il générera une expression qui ressemblera à
public static Expression<Func<T, T, bool>> CreateAreEqualExpression<T>( params Expression<Func<T, object>>[] toExclude) { var exclude = toExclude .Select(e => { // for properties that is value types (int, DateTime and so on) var name = ((e.Body as UnaryExpression)?.Operand as MemberExpression)?.Member.Name; if (name != null) return name; // for properties that is reference type return (e.Body as MemberExpression)?.Member.Name; }) .Where(n => n != null) .Distinct() .ToArray(); var type = typeof(T); var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => !exclude.Contains(p.Name)) .ToArray(); /* rest of code is unchanged */ }
L'utilisation est simple
var comporator = CreateAreEqualExpression<Component>("Id", "DateCreated") .Compile(); // save compiled comparator somewhere to use it again later var areEqual = comporator(comp_InApp, comp_InDb);
Vous pouvez utiliser les méthodes
Equals
etGetHashCode
, ou vous pouvez utiliser une bibliothèque d'égalité qui peut effectuer la comparaison pour vous.Copie possible de Comparaison des propriétés d'objet en c # . Vérifiez la réponse avec 64 votes positifs. des trucs comme ça se font facilement avec certaines bibliothèques.
N'utilisez pas de chaîne pour stocker un
DateHeure