Comparing two complex objects, one from DB and one from input - c#

I have a program that takes in a file, does some data crunching and then compares the result with what is in the DB.
Object
public class ReleaseDates
{
public int Id { get; set; }
public string MovieName { get; set; }
public string Country { get; set; }
public DateTime ReleaseDate { get; set; }
public string AlternateSource { get; set; }
}
It is very likely that the MovieName will be the same as what is in the DB but the ReleaseDate could change.
How can I compare what I grab from the DB to a ReleaseDate object list?
Example
public bool Compare(ReleaseDates original, ReleaseDates newObj)
{
if (original.AlternateSource != newDate.AlternateSource)
{
return false;
}
if (original.Country != newDate.Country)
{
return false;
}
if (original.MovieName != newDate.MovieName)
{
return false;
}
if (original.ReleaseDate != newDate.ReleaseDate)
{
return false;
}
return true;
}
How I am getting the data from the DB:
public List<ReleaseDates> GetAllReleaseDates()
{
return Db.ReleaseDates.ToList(); // Db is my DataContext
}
The above example is to compare for a single instance of ReleaseDates, but how can I compare a list? I cannot order the List since there will be duplicates with the same MovieName but different ReleaseDate and AlternateSource.
Update
Sorry I have asked the wrong question.
What I want to do is compare the DB list with the new list and if they are different, remove it from the DB and insert the new item.
E.g.
public void Example(ReleaseDates A, ReleaseDates B)
{
if(A.MovieName != B.MovieName) // But need to compare all properties
{
Db.ReleaseDates.Remove(A);
Db.ReleaseDates.Add(B);
Db.SaveChanges();
}
}

public bool Compare(List<ReleaseDates> A, List<ReleaseDates> B)
{
if ( A.Count != B.Count ) return false;
foreach (ReleaseDates aElement in A)
{
if ( !B.Any ( bElement => Compare( aElement, bElement ) return false;
}
}

It would be better if you treat your collections as sets. You can override the equals method of ReleaseDates class (I feel Movie is a better name for this class) and add the elements of each collection to a HashSet.
You can use HashSet.SetEquals method to check for equality.

Related

Convert Entity data model to Data Transfer Object

I have these two classes
enum CustomerType {
CitizenBank = 0,
Wellsfargo = 1
}
public abstarct class CustomerDto {
int customerId {
get;
set;
}
string customerName {
get;
set;
}
string CustometAddress {
get;
set;
}
int CustomerTypeId {
get;
set;
}
}
public CitizenBank: CustomerDto {}
public Wellsfargo: CustomerDto {}
Public Class CustomerEntity {
int customerId {
get;
set;
}
string customerName {
get;
set;
}
string CustometAddress {
get;
set;
}
int CustomerTypeId {
get;
set;
}
}
I wrote a class to convert from entity to DTO
public class EntityModelToModel {
///Method to convert
public CustomerDto ToDto(CustomerEntity customerEntity) {
/// returns type customerDto based on customertypeid
switch (CustomerType) {
case Wellsfargo
return New Wellsfargo()
case citizen
return new citizen() //calls method that converts from customer Entity to citizen
}
}
I have method to check if my types match
public bool CanExecute(CustomerEntity customerEntity) {
foreach(var customerType in Enum.GetValues(typeof(Enums.customerType) if (customerEntity.CustomerType == customerType)
return true
else
false
}
}
Now my calling code I have array of CustomerEntity[] which have two items of customerid for wellsfargo and citizens. I want to do this
var res = CustomerEntity[].where(x => EntityModelToModel.CanExecute(x).Select(x => EntityModelToModel.ToDto(x))
My problem is:
If my array has two items this only checks the first items and returns.
What I want is it should check for two items and return them.
I think that you should change your CanExecute method like this:
public static class EntityModelToModel
{
// ...
public static bool CanExecute(CustomerEntity customerEntity)
{
foreach (var customerType in Enum.GetValues(typeof(CustomerType)))
{
if (customerEntity.CustomerTypeId == (int)customerType)
{
return true;
}
}
return false;
}
}
Because your method break execution flow after first check.

How to check if item is already in list in repository?

Ok, so there are a few excepotions here, I cannot use List<Dvd> Dvds = _dvds.ReadAll(); in DvdController.cs and check to see if it contains the dvd info if dvd is already in the list. Even if I did do that, it does not work as I intended it to do. Even if I check to see if the info is in the list and try to stop it, it still adds it to a list. The Dvd.cs does increment the Id by one by the way. I would like to know what would be the solution to this?
DvdController.cs
...
private void CreateDvd() //Create
{
var myView = new DvdView();
var dvdInfos = myView.GetNewDvdInfo();
_dvds.Create(dvdInfos);
DisplayDvds();
}
...
DvdRepository.cs
public class DvdRepository
{
private static List<Dvd> dvds = new List<Dvd>()
{
new Dvd("Batman", 2010, "Bruce", 4 ),
new Dvd("Superman", 2009, "John", 4),
new Dvd("Wonderwoman", 2012, "Omar", 4)
};
public Dvd Create(Dvd dvd)
{
if (dvds.Contains(dvd))
{
Console.WriteLine("duplicate"); //not working
}
else
dvds.Add(dvd);
return dvds.FirstOrDefault(d => d.Id == dvd.Id);
}
public List<Dvd> ReadAll()
{
return dvds;
}
...
Dvd.cs
public class Dvd
{
public Dvd(string title, int releaseyear, string director, float rating)
{
Id = Interlocked.Increment(ref globalId);
Title = title;
ReleaseYear = releaseyear;
Director = director;
Rating = rating;
}
public static int globalId;
public int Id { get; private set; }
public string Title { get; set; }
public int ReleaseYear { get; set; }
public string Director { get; set; }
public float Rating { get; set; }
Your check of if (dvds.Contains(dvd)) is looking for that specific object reference. Unless you pass in the actual object that is in the list already, it won't work.
You need to check a unique identifying property of the Dvd. For this you would want to use the .Any() method.
if (dvds.Any(x => x.Title == dvd.Title))
Another solution that requires a bit more code upfront but will likely help in other scenarios in the future is to override the Equals and GetHashCode methods on the Dvd class. By default, objects use a reference comparison to determine equality. By overriding these methods, we can use our own logic to determine if two Dvds are equal.
In the example below, I'm using the fields Title, ReleaseYear, and Director, but you could add others as you see fit. I also implemented IEquatable<Dvd> because it's pretty simple (just requires adding an Equals method that takes an object of type Dvd) and it goes along well with the object.Equals implementation:
public class Dvd : IEquatable<Dvd>
{
public Dvd(string title, int releaseyear, string director, float rating)
{
Id = Interlocked.Increment(ref globalId);
Title = title;
ReleaseYear = releaseyear;
Director = director;
Rating = rating;
}
public static int globalId;
public int Id { get; private set; }
public string Title { get; set; }
public int ReleaseYear { get; set; }
public string Director { get; set; }
public float Rating { get; set; }
public bool Equals(Dvd other)
{
return other != null &&
Title == other.Title &&
ReleaseYear == other.ReleaseYear &&
Director == other.Director;
}
public override bool Equals(object obj)
{
return Equals(obj as Dvd);
}
public override int GetHashCode()
{
return ((Title?.GetHashCode() ?? 17) * 17 +
ReleaseYear.GetHashCode()) * 17 +
(Director?.GetHashCode() ?? 17);
}
}
With these changes in place, we don't have to worry about remembering which fields we need to compare when evaluating two Dvd objects in a Linq query (and if we want to add more properties for comparison, we just do it in one place rather than searching throughout our code), and we can do things like if (firstDvd.Equals(secondDvd)) { // do something if they're equal } .
Now we can use the Contains method as defined in your original code. For example:
private static void Main()
{
var repo = new DvdRepository();
repo.Create(new Dvd("Batman", 2010, "Bruce", 2));
}
Outputs to the console: "duplicate"

Check if 2 objects contain the same data in fields

I have a Pharmacy class which contains lots of properties, and a Pharmacy is declared as unique by having the ID property as a key.
I have code in place which fetches all rows in a table from MySQL back to Pharmacy objects with their properties.
I want compare two List<Pharmacy> objects for the entries in them and check if the same ID exists in both tables, if it doesn't exist then add it to a new List<Pharmacy. If the ID exists in both but the data in the objects differs, then save that object to a new List<Pharmacy aswell.
This is how the class looks like.
public class Pharmacy
{
[Key]
public string Tunniste { get; set; }
public string Lyhenne { get; set; }
public string PitkaNimi { get; set; }
public string YlempiYksikko { get; set; }
public string Hierarkiataso { get; set; }
public string VoimassaoloAlkaa { get; set; }
public string VoimassaoloPaattyy { get; set; }
...
}
It's in Finnish but I hope you can live with that.
Here's how I've tried to check if they're identical.
for (int i = 0; i != pharmacyListFromArchive.Count; i++)
{
if (pharmacyListFromArchive[i].Equals(pharmacyListFromNew[i]))
{
Console.WriteLine("Objects are identical.");
}
else
{
Console.WriteLine("Objects are NOT identical. {0} - {1}", pharmacyListFromArchive[i].Tunniste, pharmacyListFromNew[i].Tunniste);
}
}
But when I run that, none of the objects register as identical even though they are identical in data. How can I work around this?
The standard implementation of Equals checks only for reference equality. What is the default behavior of Equals Method?
You can either override the behavior of Equals. Guidelines for Overriding Equals() and Operator == (C# Programming Guide).
public class Pharmacy {
// fields ...
public override bool Equals(object obj) {
// If parameter is null return false.
if (obj == null) {
return false;
}
// If parameter cannot be cast to Pharmacy return false.
Pharmacy p = obj as Pharmacy;
if ((System.Object)p == null) {
return false;
}
// Return true if the fields match:
return p.Lyhenne == this.Lyhenne &&
p.PitkaNimi == this.PitkaNimi
// && etc...
;
}
public override int GetHashCode() {
return Lyhenne.GetHashCode() ^ PitkaNimi.GetHashCode() /* ^ etc ... */;
}
}
Or you implement a custom IEqualityComparer IEqualityComparer Interface. This might be preferable if your ORM Mapper relies on the default equals (like Entity Framework does).

c# Check if custom class is in list<t>

I have a list of custom class called List<Notifications>.
The class is below:
public class Notification
{
public enum Type {
Promotion,
Other
}
public string ID { get; set; }
public string Headline { get; set; }
public string Detail { get; set; }
public Type NotificationType { get; set; }
}
Before adding an instance of the Notification class to my custom list, I want to check if it is already in the list.
What is the best way to achieve this?
You can use 1.) Contains, but then you have to override Equals (+ GethashCode).
bool contains = list.Contains(someNotificationInstance);
For example:
public class Notification
{
public enum Type {
Promotion,
Other
}
public string ID { get; set; }
public string Headline { get; set; }
public string Detail { get; set; }
public Type NotificationType { get; set; }
public override bool Equals(object obj)
{
return obj is Notification && string.Equals(ID, ((Notification)obj).ID);
}
public override int GetHashCode()
{
return ID == null ? 0 : ID.GetHashCode();
}
}
2.) another option is to provide a custom IEqualityComparer<Notification> for Contains:
public class NotificationComparer : IEqualityComparer<Notification>
{
public bool Equals(Notification x, Notification y)
{
return x.ID == y.ID;
}
public int GetHashCode(Notification obj)
{
return obj.ID == null ? 0 : obj.ID.GetHashCode();
}
}
On this way you don't need to modify the original class. You can use it in this way:
bool contains = list.Contains(someInstance, new NotificationComparer());
3.) Probably the easiest approach is using Enumerable.Any:
bool contains = list.Any(n => someInstance.ID == n.ID);
4.) The most efficient approach is using a set if no duplicates are allowed in the collection anyway. Then you can use the first or second approaches for a HashSet<T>:
var set = new HashSet<Notification>(new NotificationComparer());
set.Add(instance1);
bool contains = !set.Add(instance2);
You can check it with Contains method.
if (!mylist.Select(l => l.ID).Contains(mynewid)) {
var item = new Notifcation();
item.ID = mynewid;
item..... // fill the rest
mylist.Add(item);
}
Maybe a better approch would be use of Dictionary.

How can I use Equals or hashcode in my following program

I want to fetch the details of manager from manager class if at run time I give kinid of employee from the employee class. How can I do this using Equals or Hashcode?
public class employee
{
public string empname { get; set;}
public string location { get; set; }
public int kinid { get; set; }
public double magkin { get; set; }
}
public class manager
{
public string magname { get; set; }
public double magkin { get; set; }
}
Dictionary<employee, manager> relation = new Dictionary<employee, manager>();
I haven't used C# in a long time, but Something like this should work:
kinidFind is the kinid you want to search for.
manager findManager(int kinidFind) {
foreach( KeyValuePair<employee, manager> i in relation) {
if (i.Key.kinid==kinidFind) {
return i.Value;
}
}
}
Assuming that kinid is a unique identifier (you don't care about other fields of employee in identifying), then on employee class you could do the following:
override int GetHashCode()
{
return kinid;
}
override bool Equals(Object obj)
{
if (obj == null) return false;
emploee emp = obj as employee;
if ((System.Object)emp == null) return false;
return (kinid == emp.kinid);
}
However, this is not a good general solution because what if later on you want to find the employee by other fields?
Consider changing that dictionary to:
Dictionary<int,manager> where the int is the kinid of the employee then it's self explanatory.
or since the Dictionary has been loaded you can Enumerate it this way as well it's just a question of feel or taste at this point from Brads answer
foreach (var pair in relation)
{
if (pair.key == kinidFind )
{
return relation[pair.key];
}
}

Categories

Resources