Created
November 10, 2020 15:55
-
-
Save vertonghenb/d1a00561e76f1b8fd26ae437a4887621 to your computer and use it in GitHub Desktop.
Value Object vs Entity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Address : ValueObject | |
{ | |
public string Street { get; init; } | |
public string ZipCode { get; init; } | |
public string Municipality { get; init; } | |
public string AddressLine1 => $"{Street}"; | |
public string AddressLine2 => $"{Country.Code}-{ZipCode} {Municipality}"; | |
/// <summary> | |
/// Entity Framework Core Constructor | |
/// </summary> | |
private Address() { } | |
public Address(string street, string zipCode, string municipalityName) | |
{ | |
Street = street; | |
ZipCode = zipCode; | |
Municipality = municipalityName; | |
} | |
public Address Copy() | |
{ | |
return new Address(Street, ZipCode, Municipality, Country); | |
} | |
protected override IEnumerable<object> GetAtomicValues() | |
{ | |
yield return Street.ToUpper(); | |
yield return ZipCode.ToUpper(); | |
yield return Municipality.ToUpper(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class Entity | |
{ | |
/// <summary> | |
/// Gets or sets the unique identifier. | |
/// </summary> | |
public int Id { get; protected set; } | |
/// <summary> | |
/// Gets or sets the created DateTime. | |
/// </summary> | |
public DateTime CreatedAt { get; set; } = DateTime.UtcNow; | |
/// <summary> | |
/// Gets or sets the updated DateTime. | |
/// </summary> | |
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; | |
public override bool Equals(object obj) | |
{ | |
var other = obj as Entity; | |
// Check if the other is null. | |
if (other is null) | |
return false; | |
// Check if the objects refer to the same alloc. in memory. | |
if (ReferenceEquals(this, other)) | |
return true; | |
// Check if the types of the objects are the same. | |
if (GetType() != other.GetType()) | |
return false; | |
// Check if the objects are transient(new). | |
// Meaning we can not really compare these 2 entities, since the Id was not yet set. | |
if (Id == 0 || other.Id == 0) | |
return false; | |
// Compare Id's. | |
return Id == other.Id; | |
} | |
public static bool operator ==(Entity a, Entity b) | |
{ | |
// Both Entities are null, so they're the same. | |
if (a is null && b is null) | |
return true; | |
// One if them is null which means we cannot compare. | |
if (a is null || b is null) | |
return false; | |
return a.Equals(b); | |
} | |
public static bool operator !=(Entity a, Entity b) | |
{ | |
return !(a == b); | |
} | |
public override int GetHashCode() | |
{ | |
// The type and identifier are the "Unique makers" | |
return (GetType().ToString() + Id).GetHashCode(); | |
} | |
public override string ToString() | |
{ | |
return $"{GetType().Name} - {Id}"; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class ValueObject | |
{ | |
protected static bool EqualOperator(ValueObject left, ValueObject right) | |
{ | |
if (left is null ^ right is null) | |
return false; | |
return left is null || left.Equals(right); | |
} | |
protected static bool NotEqualOperator(ValueObject left, ValueObject right) | |
{ | |
return !(EqualOperator(left, right)); | |
} | |
protected abstract IEnumerable<object> GetAtomicValues(); | |
public override bool Equals(object obj) | |
{ | |
if (obj == null || obj.GetType() != GetType()) | |
{ | |
return false; | |
} | |
ValueObject other = (ValueObject)obj; | |
IEnumerator<object> thisValues = GetAtomicValues().GetEnumerator(); | |
IEnumerator<object> otherValues = other.GetAtomicValues().GetEnumerator(); | |
while (thisValues.MoveNext() && otherValues.MoveNext()) | |
{ | |
if (thisValues.Current is null ^ otherValues.Current is null) | |
return false; | |
if (thisValues.Current != null && !thisValues.Current.Equals(otherValues.Current)) | |
return false; | |
} | |
return !thisValues.MoveNext() && !otherValues.MoveNext(); | |
} | |
public override int GetHashCode() | |
{ | |
return GetAtomicValues() | |
.Select(x => x != null ? x.GetHashCode() : 0) | |
.Aggregate((x, y) => x ^ y); | |
} | |
public static bool operator !=(ValueObject a, ValueObject b) | |
{ | |
return !(a == b); | |
} | |
public static bool operator ==(ValueObject a, ValueObject b) | |
{ | |
if (a is null && b is null) | |
return true; | |
if (a is null || b is null) | |
return false; | |
return a.Equals(b); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment