Compare One Model Class to Another C# - c#

At the moment I currently have a CompanyModel that looks like so;
public class CompanyModel
{
public string CompanyID { get; set; }
public string CompanyName { get; set; }
public string CompanyAddr1 { get; set; }
public string CompanyAddr2 { get; set; }
public string CompanyTown { get; set; }
public string CompanyCounty { get; set; }
public string CompanyPcode { get; set; }
public string CompanyTelephone { get; set; }
public string CompanyAltTelephone { get; set; }
public string CompanyFax { get; set; }
public string CompanyEmail { get; set; }
public string CompanyWhoEntered { get; set; }
public DateTime CompanyDateEntered { get; set; }
public string CompanyTimeEntered { get; set; }
public string CompanyGeographicArea { get; set; }
public string CompanySearchName { get; set; }
}
What I would like to do is initialise two CompanyModels and compare the contents of both to ensure that both Companies have exactly the same data in their fields. Currently I am doing an absolutely horrendous concatenation of If statements as I am unsure of another way. This currently looks like so;
if (eCDetails.CompanyName == cCompanyDetails.CompanyName)
{
if (eCDetails.CompanyName == cCompanyDetails.CompanyName)
{
if (eCDetails.CompanyAddr1 == cCompanyDetails.CompanyName)
{
and so on and so forth (it's terrible). Is there an easier to way to ensure that both CompanyModels are equivalent?

How about using the conditional-AND (&&) operator?
if (eCDetails.CompanyName == cCompanyDetails.CompanyName &&
eCDetails.CompanyName == cCompanyDetails.CompanyName &&
eCDetails.CompanyAddr1 == cCompanyDetails.CompanyName &&
// etc...
If you have ReSharper, you can use it to auto-generate this code (and more) for you.

You are trying to write an equals method ?
You can make something like that :
if (eCDetails.CompanyName != cCompanyDetails.CompanyName)
{ return false;
}
if (eCDetails.CompanyName != cCompanyDetails.CompanyName)
{return false;
}
...
return true;
There's no many option to do what you want :)

try this .. also you have to ignore some properties
public static bool PublicInstancePropertiesEqual<T>(this T self, T to, params string[] ignore) where T : class
{
if (self != null && to != null)
{
var type = typeof(T);
var ignoreList = new List<string>(ignore);
var unequalProperties =
from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where !ignoreList.Contains(pi.Name)
let selfValue = type.GetProperty(pi.Name).GetValue(self, null)
let toValue = type.GetProperty(pi.Name).GetValue(to, null)
where selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))
select selfValue;
return !unequalProperties.Any();
}
return self == to;
}
Orginal thread
Happy coding

You may also implement Equals ony youd model-class:
class CompanyModel{
public override bool Equals(object other) {
var m = (CompanyModel) other;
if (m == null) return false;
return this.CompanyName == m.CompanyName &&
this.CompanyName == m.CompanyName &&
this.CompanyAddr1 == m.CompanyAddr1 // ...
}
}
Now you can use myModelInstance.Equals(anotherInstance).

Related

Check if two instances of same class have same data in C#

I'm trying to validate if both my objects have the same values.
here's my class
public class myclass
{
public List<c1> List1{ get; set; }
public List<c2> List2{ get; set; }
public List<c3> List3{ get; set; }
}
public class c1
{
public int Number{ get; set; }
public string Name{ get; set; }
public bool IsAvailable{ get; set; }
}
public class c2
{
public int Id{ get; set; }
public string Text{ get; set; }
public GUID Guid{ get; set; }
}
public class c3
{
public int? Age{ get; set; }
public string Role{ get; set; }
public bool IsDeleted{ get; set; }
}
I have 2 instances of this class and I want to compare the data between both the instances and check if they both are the same or not.
I've tried Serializing both the objects and comparing but that's not working as the items in the list can be in a different order.
I've also tried getting HashSet of individual lists and checking if they are equal.
var s1 = new HashSet<c1>(list1);
var s2= new HashSet<c1>(list2);
return s1.SetEquals(s2);
One solution would be to first order the lists using a standard order, like numeric or alphabetic depending on the types, and then trying something like this
if (myclassInstance1.list1.SequenceEqual(myclassInstance2.list1))
{
//Repeat the cycle 2 more times and then //your code
}
Since this one works comparing the sequence you need to first order the lists and to do that you can maybe use this
EDIT: This is the documentation for the list.sequenceEquals() method
The best way to do this is if you explicitly implement the models with IEqualityComparer in .NET.
using System;
using System.Collections.Generic;
public class Program
{
public class MyClass
{
public List<C1> C1List { get; set; }
public List<C2> C2List { get; set; }
}
public class C1 : IEqualityComparer<C1>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Equals(C1 x, C1 y)
{
if(string.Equals(x.FirstName, y.FirstName, StringComparison.OrdinalIgnoreCase)
&& string.Equals(x.LastName, y.LastName, StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
public int GetHashCode(C1 c)
{
return c.FirstName.Length * c.LastName.Length;
}
}
public class C2 : IEqualityComparer<C2>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Equals(C2 x, C2 y)
{
if(string.Equals(x.FirstName, y.FirstName, StringComparison.OrdinalIgnoreCase)
&& string.Equals(x.LastName, y.LastName, StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
public int GetHashCode(C2 c)
{
return c.FirstName.Length * c.LastName.Length;
}
}
}
The IEqualityComparer will give you full control on "the parameters based on which you call 2 objects equal".
As for the above implementation, I have considered the 2 objects are equal if the FirstName and the LastName are same.
Try to order the list,and then compare the data in it:
List<c1> l1 = list1.OrderBy(c => c.Number).ToList();
List<c1> l2 = list2.OrderBy(c => c.Number).ToList();
bool equalValue = true;
if (l1.Count() == l2.Count()) {
for (int i = 0; i < l1.Count(); i++){
if (l1[i].IsAvailable != l2[i].IsAvailable || l1[i].Number != l2[i].Number || l1[i].Name != l2[i].Name)
{
equalValue = false;
break;
}
}
}
else {
equalValue = false;
}
return equalValue;

Object comparison but ignore case of strings

I have an object like so:
public class MyObject {
public string firstname { get; set; }
public string lastname { get; set; }
public int age { get; set; }
public string occupation { get; set; }
}
I am trying to do a comparison of two objects but I want all strings to ignore case. Unfortunately the following won't compile:
// Does NOT allow me to call using ignore case
if (myObject1.Equals(myObject2, StringComparison.OrdinalIgnoreCase)) {
Console.WriteLine("Match!");
}
Is there a way to accomplish this without manually checking each property in the object?
You can override the Equals() method of your class (it is a method that every object has). Everything is well described in the documentation.
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if ((obj == null) || ! this.GetType().Equals(obj.GetType()))
{
return false;
}
else {
Point p = (Point) obj;
return (x == p.x) && (y == p.y);
}
}
To compare equality, you can implement Equals, let's do it with a help of
IEquatable<MyObject> interface:
public class MyObject : IEquatable<MyObject> {
public string firstname { get; set; }
public string lastname { get; set; }
public int age { get; set; }
public string occupation { get; set; }
public bool Equals(MyObject other) {
if (ReferenceEquals(this, other))
return true;
if (null == other)
return false;
return
string.Equals(firstname, other.firstname, StringComparison.OrdinalIgnoreCase) &&
string.Equals(lastname, other.lastname, StringComparison.OrdinalIgnoreCase) &&
string.Equals(occupation, other.occupation, StringComparison.OrdinalIgnoreCase) &&
age == other.age;
}
public override bool Equals(object obj) => obj is MyObject other && Equals(other);
public override int GetHashCode() =>
(firstname?.GetHashCode(StringComparison.CurrentCultureIgnoreCase) ?? 0) ^
(lastname?.GetHashCode(StringComparison.CurrentCultureIgnoreCase) ?? 0) ^
(occupation?.GetHashCode(StringComparison.CurrentCultureIgnoreCase) ?? 0) ^
age;
}
then you can use the customized Equals
if (myObject1.Equals(myObject2)) {...}

How to update data in a related table in EF?

There are two such models:
public class Form
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid FormId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public List<BlockWorkingForm> BlocksWorkingForm { get; set; }
}
public class BlockWorkingForm
{
[Key]
[Column(Order = 1)]
public string Header { get; set; }
[Key]
[Column(Order = 2)]
public Guid FormId { get; set; }
public Form Form { get; set; }
public string Field { get; set; }
public bool MandatoryQuestion { get; set; }
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is BlockWorkingForm m))
{
return false;
}
return m.Header == this.Header
&& m.Field == this.Field
&& m.Type == this.Type
&& m.MandatoryQuestion == this.MandatoryQuestion;
}
}
And there is such a method for updating the model.
public void UpdateForm(Form form)
{
EditorFormContext context = new EditorFormContext();
var formDb = this.context.Forms.Include(x => x.BlocksWorkingForm).Single(x => x.FormId == form.FormId);
this.context.Entry(formDb).CurrentValues.SetValues(form);
foreach (var itemForm in form.BlocksWorkingForm)
{
if (itemForm.FormId == Guid.Empty)
{
itemForm.FormId = formDb.FormId;
this.context.BlocksWorkingForm.Add(itemForm);
}
foreach (var itemFormDb in formDb.BlocksWorkingForm)
{
if (itemForm.Header != itemFormDb.Header)
{
continue;
}
if (!itemForm.Equals(itemFormDb))
{
this.context.Entry(itemFormDb)
.CurrentValues.SetValues(itemForm);
}
}
}
this.context.SaveChanges()
}
Now it only allows updating the Title and Description fields in the Database in the Form, as well as adding new blocks (BlockWorkingForm) for the form. But it is still necessary to implement the removal of these blocks.
To remove blocks, I need to compare what is in the database and what came in the Update method, but how can this be done?
This this.context.Entry(formDb).CurrentValues.SetValues(form); is where your properties (Title and Description) are set in the DB object. But The list of BlocksWorkingForm is not set (or not set properly).
If you add the BlocksWorkingForms in the form yourself, the insert should work properly.
This should work.
public void UpdateForm(Form form)
{
EditorFormContext context = new EditorFormContext();
var formDb = this.context.Forms.Include(x => x.BlocksWorkingForm).Single(x => x.FormId == form.FormId);
this.context.Entry(formDb).CurrentValues.SetValues(form);
formDb.BlocksWorkingForm = form.BlocksWorkingForm;
this.context.SaveChanges()
}

How to implement IComparable to all properties?

I have a class that contains the details of a Match, the structure is this:
public class Match
{
public string TeamHome { get; set; }
public string TeamAway { get; set; }
public string Result { get; set; }
public League League { get; set; }
}
public class League
{
public string Name { get; set; }
public string Country{ get; set; }
}
I bound a list of Match to a DataGrid, but I have a problem, when I apply the sorting on that DataGrid I get:
at least one object must implement IComparable
this happen only when I have already added items to the Matches collection, that is the collection bounded by the DataGrid and is defined in this way:
List<Match> Matches = new List<Match>();
I tried to fix this error implementing the IComparable interface:
public class Match : IComparable<Match>
{
public string TeamHome { get; set; }
public string TeamAway { get; set; }
public string Result { get; set; }
public League League { get; set; }
public int CompareTo(Match other)
{
return this.CompareTo(other);
}
}
the error still happen.
So I need to ask these questions:
Should I implement IComparable to all properties?
How can I investigate more?
Thanks for any help.
You need to add your own implementation to CompareTo(Match match) method
Something like:
public int CompareTo(object obj)
{
Match match = obj as Match;
if(match != null)
{
return (TeamHome == match.TeamHome
&& TeamAway == match.TeamAway
&& Result == match.Result
&& League.GetHashCode() == match.League.GetHashCode())
? 0 : -1;
}
return -1;
}
And in your class declaration:
public class Match : IComparable
without the <Match>
But in this case i think it would make more sense to overload the Equals operator like this:
public override bool Equals(object other)
{
Match match = other as Match;
if(match != null)
{
return TeamHome == match.TeamHome
&& TeamAway == match.TeamAway
&& Result == match.Result
&& League.GetHashCode() == match.League.GetHashCode();
}
return false;
}

LINQ Intersection not working

I have two list that i want to compare. In one i have a small amount of objects and in the other im sure i have the objects from the first list plus others.
Im trying to do an intersection to get the objects from the second list that are in my first list.To do that i have the object inside the two list is of type
public class ReportDataImportant : ReportData
{
public String IdTitular { get; set; }
public String Identificacion { get; set; }
public String IndicadorPersona { get; set; }
public String Titular { get; set; }
public decimal Porcentaje { get; set; }
public int Cotitulares { get; set; }
public String IndicadorNacionalidad { get; set; }
public String Nacionalidad { get; set; }
}
I have also a comparer class like this:
public class ReportDataComparer : IEqualityComparer<ReportDataImportant>
{
public bool Equals(ReportDataImportant x, ReportDataImportant y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) ||
Object.ReferenceEquals(y, null))
return false;
return x.Identificacion.Equals(y.Identificacion);
}
public int GetHashCode(ReportDataImportant obj)
{
if (Object.ReferenceEquals(obj, null)) return 0;
return obj.Identificacion.GetHashCode();
}
}
An to make the intersection i call it with this expresion :
var reult = _list1.Intersect(List2, new ReportDataComparer()).ToList();
However im not getting the result im expecting. Does somebody know what is happening?

Categories