mirror of
https://github.com/collinbarrett/FilterLists.git
synced 2026-03-11 09:04:27 +00:00
fix(dir): 🐛 capture new ViewUrlId in Change using hi/lo to predetermine id
This commit is contained in:
parent
ccb7ca3c03
commit
721926c8b5
10 changed files with 38 additions and 208 deletions
|
|
@ -14,7 +14,7 @@
|
|||
namespace FilterLists.Directory.Infrastructure.Migrations.Migrations
|
||||
{
|
||||
[DbContext(typeof(QueryDbContext))]
|
||||
[Migration("20211205154614_Initial")]
|
||||
[Migration("20211205175314_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
|
|
@ -27,6 +27,10 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|||
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "aggregate_type", new[] { "filter_list", "language", "license", "maintainer", "software", "syntax", "tag" });
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.HasSequence("EntityFrameworkHiLoSequence-FilterListViewUrl")
|
||||
.StartsAt(3000L)
|
||||
.IncrementsBy(3);
|
||||
|
||||
modelBuilder.Entity("FilterLists.Directory.Infrastructure.Persistence.Queries.Entities.Change", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
|
@ -676,7 +680,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property<long>("Id"));
|
||||
NpgsqlPropertyBuilderExtensions.UseHiLo(b1.Property<long>("Id"), "EntityFrameworkHiLoSequence-FilterListViewUrl");
|
||||
|
||||
b1.Property<short>("Primariness")
|
||||
.ValueGeneratedOnAdd()
|
||||
|
|
@ -15,6 +15,11 @@ protected override void Up(MigrationBuilder migrationBuilder)
|
|||
migrationBuilder.AlterDatabase()
|
||||
.Annotation("Npgsql:Enum:aggregate_type", "filter_list,language,license,maintainer,software,syntax,tag");
|
||||
|
||||
migrationBuilder.CreateSequence(
|
||||
name: "EntityFrameworkHiLoSequence-FilterListViewUrl",
|
||||
startValue: 3000L,
|
||||
incrementBy: 3);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "languages",
|
||||
columns: table => new
|
||||
|
|
@ -355,8 +360,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
|
|||
name: "filter_list_view_urls",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
id = table.Column<long>(type: "bigint", nullable: false),
|
||||
filter_list_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
segment_number = table.Column<short>(type: "smallint", nullable: false, defaultValue: (short)1),
|
||||
primariness = table.Column<short>(type: "smallint", nullable: false, defaultValue: (short)1),
|
||||
|
|
@ -608,6 +612,9 @@ protected override void Down(MigrationBuilder migrationBuilder)
|
|||
|
||||
migrationBuilder.DropTable(
|
||||
name: "licenses");
|
||||
|
||||
migrationBuilder.DropSequence(
|
||||
name: "EntityFrameworkHiLoSequence-FilterListViewUrl");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
namespace FilterLists.Directory.Infrastructure.Migrations.Migrations
|
||||
{
|
||||
[DbContext(typeof(QueryDbContext))]
|
||||
[Migration("20211205154639_SeedData")]
|
||||
[Migration("20211205175350_SeedData")]
|
||||
partial class SeedData
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
|
|
@ -27,6 +27,10 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|||
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "aggregate_type", new[] { "filter_list", "language", "license", "maintainer", "software", "syntax", "tag" });
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.HasSequence("EntityFrameworkHiLoSequence-FilterListViewUrl")
|
||||
.StartsAt(3000L)
|
||||
.IncrementsBy(3);
|
||||
|
||||
modelBuilder.Entity("FilterLists.Directory.Infrastructure.Persistence.Queries.Entities.Change", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
|
@ -66050,7 +66054,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property<long>("Id"));
|
||||
NpgsqlPropertyBuilderExtensions.UseHiLo(b1.Property<long>("Id"), "EntityFrameworkHiLoSequence-FilterListViewUrl");
|
||||
|
||||
b1.Property<short>("Primariness")
|
||||
.ValueGeneratedOnAdd()
|
||||
|
|
@ -25,6 +25,10 @@ protected override void BuildModel(ModelBuilder modelBuilder)
|
|||
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "aggregate_type", new[] { "filter_list", "language", "license", "maintainer", "software", "syntax", "tag" });
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.HasSequence("EntityFrameworkHiLoSequence-FilterListViewUrl")
|
||||
.StartsAt(3000L)
|
||||
.IncrementsBy(3);
|
||||
|
||||
modelBuilder.Entity("FilterLists.Directory.Infrastructure.Persistence.Queries.Entities.Change", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
|
@ -66048,7 +66052,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
|
|||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property<long>("Id"));
|
||||
NpgsqlPropertyBuilderExtensions.UseHiLo(b1.Property<long>("Id"), "EntityFrameworkHiLoSequence-FilterListViewUrl");
|
||||
|
||||
b1.Property<short>("Primariness")
|
||||
.ValueGeneratedOnAdd()
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ public virtual void Configure(EntityTypeBuilder<FilterList> builder)
|
|||
b =>
|
||||
{
|
||||
b.ToTable($"{nr.RewriteName(nameof(FilterListViewUrl))}s");
|
||||
b.Property(u => u.Id)
|
||||
.UseHiLo($"EntityFrameworkHiLoSequence-{nameof(FilterListViewUrl)}");
|
||||
b.Property(u => u.SegmentNumber)
|
||||
.HasDefaultValue(1);
|
||||
b.Property(u => u.Primariness)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ public override Task<int> SaveChangesAsync(
|
|||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.HasSequence($"EntityFrameworkHiLoSequence-{nameof(FilterListViewUrl)}")
|
||||
.StartsAt(3000)
|
||||
.IncrementsBy(3);
|
||||
modelBuilder.ApplyConfigurationsFromAssembly(
|
||||
GetType().Assembly,
|
||||
type => type.Namespace == typeof(FilterListTypeConfiguration).Namespace);
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ public override void Configure(EntityTypeBuilder<FilterList> builder)
|
|||
b =>
|
||||
{
|
||||
b.ToTable($"{nr.RewriteName(nameof(FilterListViewUrl))}s");
|
||||
b.Property(u => u.Id)
|
||||
.UseHiLo($"EntityFrameworkHiLoSequence-{nameof(FilterListViewUrl)}");
|
||||
b.Property(u => u.SegmentNumber)
|
||||
.HasDefaultValue(1);
|
||||
b.Property(u => u.Primariness)
|
||||
|
|
|
|||
|
|
@ -1,79 +1,8 @@
|
|||
namespace FilterLists.SharedKernel.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/master/CSharpFunctionalExtensions/Entity/Entity.cs
|
||||
/// </summary>
|
||||
public abstract class Entity<TId>
|
||||
public abstract class Entity
|
||||
{
|
||||
protected Entity() { }
|
||||
public long Id { get; protected init; }
|
||||
|
||||
protected Entity(TId id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public virtual TId Id { get; protected set; } = default!;
|
||||
|
||||
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) { }
|
||||
// TODO: More fully implement (e.g., https://enterprisecraftsmanship.com/posts/entity-base-class/). Make sure equality doesn't break duplicate ViewUrls when adding newly created FilterList to DbContext (related to hi/lo and/or NRTs).
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,132 +1,7 @@
|
|||
namespace FilterLists.SharedKernel.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/master/CSharpFunctionalExtensions/ValueObject/ValueObject.cs
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class ValueObject : IComparable, IComparable<ValueObject>
|
||||
// TODO: implement value equality (e.g., https://enterprisecraftsmanship.com/posts/value-object-better-implementation/)
|
||||
public abstract class ValueObject
|
||||
{
|
||||
private int? _cachedHashCode;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public virtual int CompareTo(ValueObject? other)
|
||||
{
|
||||
return CompareTo(other as object);
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<object?> GetEqualityComponents();
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetUnproxiedType(this) != GetUnproxiedType(obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var valueObject = (ValueObject)obj;
|
||||
|
||||
return GetEqualityComponents()
|
||||
.SequenceEqual(valueObject.GetEqualityComponents());
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
_cachedHashCode ??= GetEqualityComponents()
|
||||
.Aggregate(
|
||||
1,
|
||||
(current, obj) =>
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (current * 23) + (obj?.GetHashCode() ?? 0);
|
||||
}
|
||||
});
|
||||
|
||||
return _cachedHashCode.Value;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
public static bool operator !=(ValueObject? a, ValueObject? b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
internal static Type? GetUnproxiedType(object? obj)
|
||||
{
|
||||
const string EFCoreProxyPrefix = "Castle.Proxies.";
|
||||
const string NHibernateProxyPostfix = "Proxy";
|
||||
|
||||
var type = obj?.GetType();
|
||||
var 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