mirror of
https://github.com/collinbarrett/FilterLists.git
synced 2026-03-11 09:04:27 +00:00
refactor(svcs): SeedWork Entity & ValueObject
This commit is contained in:
parent
b01c932a6d
commit
43c2036a7e
6 changed files with 160 additions and 28 deletions
|
|
@ -1,6 +1,8 @@
|
|||
namespace FilterLists.Directory.Domain.Aggregates.Changes;
|
||||
using FilterLists.SharedKernel.Domain.SeedWork;
|
||||
|
||||
public abstract class Change
|
||||
namespace FilterLists.Directory.Domain.Aggregates.Changes;
|
||||
|
||||
public abstract class Change : Entity
|
||||
{
|
||||
public string? Reason { get; protected init; }
|
||||
public DateTime SubmittedAt { get; protected init; } = DateTime.UtcNow;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
using FilterLists.Directory.Domain.Aggregates.Changes;
|
||||
using FilterLists.Directory.Domain.Aggregates.Licenses;
|
||||
using FilterLists.SharedKernel.Domain.SeedWork;
|
||||
|
||||
namespace FilterLists.Directory.Domain.Aggregates.FilterLists;
|
||||
|
||||
public class FilterList : IRequireChangeApproval<FilterListChange>
|
||||
public class FilterList : Entity, IRequireChangeApproval<FilterListChange>
|
||||
{
|
||||
protected FilterList() { }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
namespace FilterLists.Directory.Domain.Aggregates.FilterLists;
|
||||
using FilterLists.SharedKernel.Domain.SeedWork;
|
||||
|
||||
public class FilterListViewUrl
|
||||
namespace FilterLists.Directory.Domain.Aggregates.FilterLists;
|
||||
|
||||
public class FilterListViewUrl : Entity
|
||||
{
|
||||
protected FilterListViewUrl() { }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
namespace FilterLists.Directory.Domain.Aggregates.Licenses;
|
||||
using FilterLists.SharedKernel.Domain.SeedWork;
|
||||
|
||||
public class License
|
||||
namespace FilterLists.Directory.Domain.Aggregates.Licenses;
|
||||
|
||||
public class License : Entity
|
||||
{
|
||||
protected License() { }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
namespace FilterLists.SharedKernel.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/master/CSharpFunctionalExtensions/Entity/Entity.cs
|
||||
/// </summary>
|
||||
public abstract class Entity<TId>
|
||||
{
|
||||
public virtual TId Id { get; protected set; } = default!;
|
||||
|
||||
protected Entity()
|
||||
{
|
||||
}
|
||||
|
||||
protected Entity(TId id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is not Entity<TId> other)
|
||||
return false;
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
return true;
|
||||
|
||||
if (ValueObject.GetUnproxiedType(this) != ValueObject.GetUnproxiedType(other))
|
||||
return false;
|
||||
|
||||
if (IsTransient() || other.IsTransient())
|
||||
return false;
|
||||
|
||||
return Id is not null && Id.Equals(other.Id);
|
||||
}
|
||||
|
||||
private bool IsTransient()
|
||||
{
|
||||
return Id is null || Id.Equals(default(TId));
|
||||
}
|
||||
|
||||
public static bool operator ==(Entity<TId>? a, Entity<TId>? b)
|
||||
{
|
||||
if (a is null && b is null)
|
||||
return true;
|
||||
|
||||
if (a is null || b is null)
|
||||
return false;
|
||||
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(Entity<TId>? a, Entity<TId>? b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (ValueObject.GetUnproxiedType(this)?.ToString() + Id).GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Entity : Entity<long>
|
||||
{
|
||||
protected Entity()
|
||||
{
|
||||
}
|
||||
|
||||
protected Entity(long id)
|
||||
: base(id)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,22 @@
|
|||
namespace FilterLists.SharedKernel.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// https://enterprisecraftsmanship.com/posts/value-object-better-implementation/
|
||||
/// https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/master/CSharpFunctionalExtensions/ValueObject/ValueObject.cs
|
||||
/// </summary>
|
||||
public abstract class ValueObject
|
||||
[Serializable]
|
||||
public abstract class ValueObject : IComparable, IComparable<ValueObject>
|
||||
{
|
||||
protected abstract IEnumerable<object> GetEqualityComponents();
|
||||
private int? _cachedHashCode;
|
||||
|
||||
protected abstract IEnumerable<object?> GetEqualityComponents();
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetType() != obj.GetType())
|
||||
{
|
||||
if (GetUnproxiedType(this) != GetUnproxiedType(obj))
|
||||
return false;
|
||||
}
|
||||
|
||||
var valueObject = (ValueObject)obj;
|
||||
|
||||
|
|
@ -26,27 +25,66 @@ public override bool Equals(object? obj)
|
|||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetEqualityComponents()
|
||||
.Aggregate(1, (current, obj) =>
|
||||
{
|
||||
unchecked
|
||||
_cachedHashCode ??= GetEqualityComponents()
|
||||
.Aggregate(
|
||||
1,
|
||||
(current, obj) =>
|
||||
{
|
||||
return (current * 23) + (obj?.GetHashCode() ?? 0);
|
||||
}
|
||||
});
|
||||
unchecked
|
||||
{
|
||||
return current * 23 + (obj?.GetHashCode() ?? 0);
|
||||
}
|
||||
});
|
||||
|
||||
return _cachedHashCode.Value;
|
||||
}
|
||||
|
||||
public virtual int CompareTo(object? obj)
|
||||
{
|
||||
var thisType = GetUnproxiedType(this);
|
||||
var otherType = GetUnproxiedType(obj);
|
||||
|
||||
if (thisType != otherType)
|
||||
return string.CompareOrdinal(thisType?.ToString(), otherType?.ToString());
|
||||
|
||||
var other = (ValueObject?)obj;
|
||||
|
||||
var components = GetEqualityComponents().ToArray();
|
||||
var otherComponents = other?.GetEqualityComponents().ToArray() ?? Array.Empty<object?>();
|
||||
|
||||
return components.Select((t, i) => CompareComponents(t, otherComponents[i]))
|
||||
.FirstOrDefault(comparison => comparison != 0);
|
||||
}
|
||||
|
||||
private static int CompareComponents(object? object1, object? object2)
|
||||
{
|
||||
if (object1 is null && object2 is null)
|
||||
return 0;
|
||||
|
||||
if (object1 is null)
|
||||
return -1;
|
||||
|
||||
if (object2 is null)
|
||||
return 1;
|
||||
|
||||
if (object1 is IComparable comparable1 && object2 is IComparable comparable2)
|
||||
return comparable1.CompareTo(comparable2);
|
||||
|
||||
return object1.Equals(object2) ? 0 : -1;
|
||||
}
|
||||
|
||||
public virtual int CompareTo(ValueObject? other)
|
||||
{
|
||||
return CompareTo(other as object);
|
||||
}
|
||||
|
||||
public static bool operator ==(ValueObject? a, ValueObject? b)
|
||||
{
|
||||
if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
|
||||
{
|
||||
if (a is null && b is null)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
|
||||
{
|
||||
if (a is null || b is null)
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
|
@ -55,4 +93,18 @@ public override int GetHashCode()
|
|||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
internal static Type? GetUnproxiedType(object? obj)
|
||||
{
|
||||
const string EFCoreProxyPrefix = "Castle.Proxies.";
|
||||
const string NHibernateProxyPostfix = "Proxy";
|
||||
|
||||
var type = obj?.GetType();
|
||||
string? typeString = type?.ToString();
|
||||
|
||||
if (typeString is not null && (typeString.Contains(EFCoreProxyPrefix) || typeString.EndsWith(NHibernateProxyPostfix)))
|
||||
return type?.BaseType;
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue