From 270bdfd97d28037d648616c7079cd9a7a11510ce Mon Sep 17 00:00:00 2001 From: DefGh Date: Fri, 1 Mar 2024 12:33:08 +0400 Subject: [PATCH] Nullable better support --- .../Converters/DirectConverter.cs | 6 +- .../Converters/EncryptedConverter.cs | 7 +- .../FilterNullablePandaBaseConverter.cs | 3 + .../Converters/FilterPandaBaseConverter.cs | 3 + .../DistinctColumnValuesExtensions.cs | 16 +-- .../Extensions/FilterExtensions.cs | 4 +- IEnumerableExtenders/IConverter.cs | 5 +- .../IEnumerableExtenders.csproj | 2 +- IEnumerableExtenders/PropertyHelper.cs | 35 +++++- .../Components/Pages/TableCompany.razor | 113 ++++++++++-------- TestFilters/Components/Pages/TestDirect.razor | 41 +++++++ TestFilters/Program.cs | 82 +++++++++++-- TestFilters/db/Company.cs | 3 + TestFilters/db/CompanyFilter.cs | 98 ++++++++++++++- TestFilters/db/PostgresContext.cs | 84 +++++++++++++ TestFilters/db/SomeClass.cs | 9 ++ 16 files changed, 434 insertions(+), 77 deletions(-) create mode 100644 TestFilters/Components/Pages/TestDirect.razor create mode 100644 TestFilters/db/SomeClass.cs diff --git a/IEnumerableExtenders/Converters/DirectConverter.cs b/IEnumerableExtenders/Converters/DirectConverter.cs index 37b00cf..d1afbd9 100644 --- a/IEnumerableExtenders/Converters/DirectConverter.cs +++ b/IEnumerableExtenders/Converters/DirectConverter.cs @@ -1,7 +1,11 @@ -namespace PandaTech.IEnumerableFilters.Converters; +using Microsoft.EntityFrameworkCore; + +namespace PandaTech.IEnumerableFilters.Converters; public class DirectConverter : IConverter { + public DbContext Context { get; set; } + public object ConvertTo(object from) { return from; diff --git a/IEnumerableExtenders/Converters/EncryptedConverter.cs b/IEnumerableExtenders/Converters/EncryptedConverter.cs index be14134..8340cbd 100644 --- a/IEnumerableExtenders/Converters/EncryptedConverter.cs +++ b/IEnumerableExtenders/Converters/EncryptedConverter.cs @@ -1,4 +1,5 @@ -using Pandatech.Crypto; +using Microsoft.EntityFrameworkCore; +using Pandatech.Crypto; namespace PandaTech.IEnumerableFilters.Converters; @@ -8,7 +9,9 @@ public class EncryptedConverter : IConverter { Key = Environment.GetEnvironmentVariable("AES_KEY") ?? "" }); - + + public DbContext Context { get; set; } + public byte[] ConvertTo(string from) { return Aes256.Encrypt(from); diff --git a/IEnumerableExtenders/Converters/FilterNullablePandaBaseConverter.cs b/IEnumerableExtenders/Converters/FilterNullablePandaBaseConverter.cs index 7685a59..3df99b4 100644 --- a/IEnumerableExtenders/Converters/FilterNullablePandaBaseConverter.cs +++ b/IEnumerableExtenders/Converters/FilterNullablePandaBaseConverter.cs @@ -1,9 +1,12 @@ using BaseConverter; +using Microsoft.EntityFrameworkCore; namespace PandaTech.IEnumerableFilters.Converters; public class FilterNullablePandaBaseConverter : IConverter { + public DbContext Context { get; set; } + public long? ConvertTo(string? from) { if (from is null) return null; diff --git a/IEnumerableExtenders/Converters/FilterPandaBaseConverter.cs b/IEnumerableExtenders/Converters/FilterPandaBaseConverter.cs index 73941e7..144ca4e 100644 --- a/IEnumerableExtenders/Converters/FilterPandaBaseConverter.cs +++ b/IEnumerableExtenders/Converters/FilterPandaBaseConverter.cs @@ -1,9 +1,12 @@ using BaseConverter; +using Microsoft.EntityFrameworkCore; namespace PandaTech.IEnumerableFilters.Converters; public class FilterPandaBaseConverter : IConverter { + public DbContext Context { get; set; } + public long ConvertTo(string from) { return PandaBaseConverter.Base36ToBase10(from)!.Value; diff --git a/IEnumerableExtenders/Extensions/DistinctColumnValuesExtensions.cs b/IEnumerableExtenders/Extensions/DistinctColumnValuesExtensions.cs index 807fbf4..53b664c 100644 --- a/IEnumerableExtenders/Extensions/DistinctColumnValuesExtensions.cs +++ b/IEnumerableExtenders/Extensions/DistinctColumnValuesExtensions.cs @@ -13,9 +13,9 @@ namespace PandaTech.IEnumerableFilters.Extensions; public static class DistinctColumnValuesExtensions { private static IQueryable GenerateBaseQueryable(this IQueryable dbSet, - List filters) where TModel : class + List filters, DbContext? context) where TModel : class { - var query = dbSet.ApplyFilters(filters); + var query = dbSet.ApplyFilters(filters, context); return query; @@ -49,7 +49,7 @@ static Type GetEnumerableType(Type type) } public static DistinctColumnValuesResult DistinctColumnValues(this IQueryable dbSet, - List filters, string columnName, int pageSize, int page) where TModel : class + List filters, string columnName, int pageSize, int page, DbContext? context) where TModel : class { var result = new DistinctColumnValuesResult(); @@ -79,7 +79,7 @@ public static DistinctColumnValuesResult DistinctColumnValues(this IQuer return result; } - var query = GenerateBaseQueryable(dbSet, filters); + var query = GenerateBaseQueryable(dbSet, filters, context); IQueryable query2; // check for ICollection<> @@ -125,11 +125,13 @@ public static DistinctColumnValuesResult DistinctColumnValues(this IQuer public static async Task DistinctColumnValuesAsync( this IQueryable dbSet, List filters, - string columnName, int pageSize, int page, CancellationToken cancellationToken = default) where TModel : class + string columnName, int pageSize, int page, DbContext? context = null, CancellationToken cancellationToken = default) where TModel : class { var result = new DistinctColumnValuesResult(); - var targetProperty = typeof(TModel).GetTargetType().GetProperties() + var targetProperty = typeof(TModel) + .GetTargetType() + .GetProperties() .Where(x => x.GetCustomAttribute() != null) .FirstOrDefault(x => x.Name == columnName); @@ -154,7 +156,7 @@ public static async Task DistinctColumnValuesAsync query2; // check for ICollection<> diff --git a/IEnumerableExtenders/Extensions/FilterExtensions.cs b/IEnumerableExtenders/Extensions/FilterExtensions.cs index 725b552..1aaf463 100644 --- a/IEnumerableExtenders/Extensions/FilterExtensions.cs +++ b/IEnumerableExtenders/Extensions/FilterExtensions.cs @@ -12,7 +12,7 @@ namespace PandaTech.IEnumerableFilters.Extensions; public static class FilterExtensions { //public static IQueryable ApplyFilters(this IQueryable dbSet, List filters) - public static IQueryable ApplyFilters(this IQueryable dbSet, List filters) + public static IQueryable ApplyFilters(this IQueryable dbSet, List filters, DbContext? context = null) { var q = dbSet; @@ -35,7 +35,7 @@ public static IQueryable ApplyFilters(this IQueryable db if (targetType.IsIEnumerable() && !mappedToPropertyAttribute.Encrypted) targetType = targetType.GetCollectionType(); var method = typeof(PropertyHelper).GetMethod("GetValues")!.MakeGenericMethod(targetType); - var values = method.Invoke(null, [filter, mappedToPropertyAttribute]); + var values = method.Invoke(null, [filter, mappedToPropertyAttribute, context]); if (mappedToPropertyAttribute.Encrypted) { diff --git a/IEnumerableExtenders/IConverter.cs b/IEnumerableExtenders/IConverter.cs index 4b04c71..b042d22 100644 --- a/IEnumerableExtenders/IConverter.cs +++ b/IEnumerableExtenders/IConverter.cs @@ -1,7 +1,10 @@ -namespace PandaTech.IEnumerableFilters; +using Microsoft.EntityFrameworkCore; + +namespace PandaTech.IEnumerableFilters; public interface IConverter { + public DbContext Context { get; set; } public TTo ConvertTo(TFrom from); public TFrom ConvertFrom(TTo to); diff --git a/IEnumerableExtenders/IEnumerableExtenders.csproj b/IEnumerableExtenders/IEnumerableExtenders.csproj index 734acb6..16d40be 100644 --- a/IEnumerableExtenders/IEnumerableExtenders.csproj +++ b/IEnumerableExtenders/IEnumerableExtenders.csproj @@ -5,7 +5,7 @@ enable enable PandaTech.IEnumerableFilters - 4.0.17 + 4.0.18 PandaTech This NuGet helps with filtering tables. https://github.com/PandaTechAM/be-lib-ienumerable-extenders-filters.git diff --git a/IEnumerableExtenders/PropertyHelper.cs b/IEnumerableExtenders/PropertyHelper.cs index b283c2a..c352bd6 100644 --- a/IEnumerableExtenders/PropertyHelper.cs +++ b/IEnumerableExtenders/PropertyHelper.cs @@ -1,5 +1,7 @@ using System.Linq.Expressions; using System.Text.Json; +using Microsoft.EntityFrameworkCore; +using Org.BouncyCastle.Asn1.X509.Qualified; using PandaTech.IEnumerableFilters.Attributes; using PandaTech.IEnumerableFilters.Converters; using PandaTech.IEnumerableFilters.Dto; @@ -10,7 +12,7 @@ namespace PandaTech.IEnumerableFilters; internal static class PropertyHelper { - public static List GetValues(this FilterDto filter, MappedToPropertyAttribute propertyAttribute) + public static List GetValues(this FilterDto filter, MappedToPropertyAttribute propertyAttribute, DbContext? context = null) { var converterType = propertyAttribute.Encrypted ? typeof(EncryptedConverter) @@ -22,6 +24,10 @@ public static List GetValues(this FilterDto filter, MappedToPropertyAttrib ? typeof(T) : converterType.GetMethod("ConvertFrom")!.ReturnType; var converter = Activator.CreateInstance(converterType); + + if (context is not null) + converter!.GetType().GetProperty("Context")!.SetValue(converter, context); + var method = converter!.GetType().GetMethods().First(x => x.Name == "ConvertTo"); var list = new List(); @@ -44,7 +50,7 @@ public static List GetValues(this FilterDto filter, MappedToPropertyAttrib if (typeof(T).EnumCheck()) return (T)Enum.Parse(typeof(T).GetEnumType(), val.GetString()!, true); - var name = attribute.Encrypted ? "String" : typeof(T).Name; + var type = attribute.Encrypted ? typeof(string) : typeof(T); if (val.ValueKind == JsonValueKind.Null) return default; @@ -52,9 +58,28 @@ public static List GetValues(this FilterDto filter, MappedToPropertyAttrib if (val.ValueKind == JsonValueKind.Undefined) return default; - return (T)(name switch + if (type == typeof(string)) + return (T)(object)(attribute.Encrypted ? val.GetString()! : val.GetString()!.ToLower()); + + if (type == typeof(int) || type == typeof(long) || type == typeof(decimal) || type == typeof(double) || type == typeof(float) || type == typeof(short) || type == typeof(byte) + || type == typeof(int?) || type == typeof(long?) || type == typeof(decimal?) || type == typeof(double?) || type == typeof(float?) || type == typeof(short?) || type == typeof(byte?)) + return (T)(object)val.GetInt64(); + + if (type == typeof(bool) || type == typeof(bool?)) + return val.GetBoolean() ? (T)(object)true : (T)(object)false; + + if (type == typeof(DateTime) || type == typeof(DateTime?)) + return (T)(object)val.GetDateTime(); + + if (type == typeof(Guid) || type == typeof(Guid?)) + return (T)(object)val.GetGuid(); + + return Activator.CreateInstance()!; + + + /*return (T)(name switch { - "String" => attribute.Encrypted ? val.GetString()! : val.GetString()!.ToLower(), + typeof(string) => attribute.Encrypted ? val.GetString()! : val.GetString()!.ToLower(), "Int32" => val.GetInt32(), "Int64" => val.GetInt64(), "Boolean" => val.GetBoolean(), @@ -64,7 +89,7 @@ public static List GetValues(this FilterDto filter, MappedToPropertyAttrib "Single" => val.GetSingle(), "Guid" => val.GetGuid(), _ => Activator.CreateInstance(typeof(T))! - }); + });*/ } public static string GetPropertyLambda(MappedToPropertyAttribute propertyAttribute) diff --git a/TestFilters/Components/Pages/TableCompany.razor b/TestFilters/Components/Pages/TableCompany.razor index 6a97759..eee4467 100644 --- a/TestFilters/Components/Pages/TableCompany.razor +++ b/TestFilters/Components/Pages/TableCompany.razor @@ -17,34 +17,50 @@ - +
- - - - - - - - - - + @foreach(var coll in Enum.GetValues(typeof(Colls)).Cast()) + { + + } + @foreach (var r in _data) { - - - - - - - - - - + @foreach(var coll in Enum.GetValues(typeof(Colls)).Cast()) + { + switch (coll) + { + case Colls.Types: + + break; + case Colls.NameEncrypted: + + break; + case Colls.SomeClass: + + break; + case Colls.SomeClassN: + + break; + case Colls.SomeClassNN: + + break; + case Colls.SomeClassList: + + break; + default: + { + var prop = r.GetType().GetProperty(coll.ToString()); + var val = prop?.GetValue(r); + + break; + } + } + } } @@ -86,12 +102,31 @@ border-radius: 5px; min-width: 10px; } + + .my-table { + border-collapse: collapse; + border: 1px solid black; + } + + .my-table th { + border: 1px solid black; + padding: 5px; + cursor: pointer; + } + + .my-table td { + border: 1px solid black; + padding: 5px; + } + + @code { enum Colls { + SomeClassList, Id, Name, NameEncrypted, @@ -100,21 +135,15 @@ Age, IsEnabled, InfoName, - NullableString + NullableString, + SomeClass, + SomeClassN, + SomeClassNN, } - readonly Dictionary _filters = new() - { - { Colls.Id, "" }, - { Colls.Name, "" }, - { Colls.Type, "" }, - { Colls.Types, "" }, - { Colls.Age, "" }, - { Colls.IsEnabled, "" }, - { Colls.NameEncrypted, "" }, - { Colls.InfoName, "" }, - { Colls.NullableString, "" } - }; + private static List _enumValues = Enum.GetValues(typeof(Colls)).Cast().ToList(); + + readonly Dictionary _filters = _enumValues.ToDictionary(x => x, _ => ""); private int _selectedPage = 1; private int _selectedPageSize = 10; @@ -126,18 +155,7 @@ private string? _filterDtosString; readonly Dictionary _distinctColumnValuesResult = - new() - { - { Colls.Id, new DistinctColumnValuesResult() }, - { Colls.Name, new DistinctColumnValuesResult() }, - { Colls.Type, new DistinctColumnValuesResult() }, - { Colls.Types, new DistinctColumnValuesResult() }, - { Colls.Age, new DistinctColumnValuesResult() }, - { Colls.IsEnabled, new DistinctColumnValuesResult() }, - { Colls.NameEncrypted, new DistinctColumnValuesResult() }, - { Colls.InfoName, new DistinctColumnValuesResult() }, - { Colls.NullableString, new DistinctColumnValuesResult() } - }; + _enumValues.ToDictionary(x => x, _ => new DistinctColumnValuesResult()); protected override async Task OnInitializedAsync() @@ -191,7 +209,7 @@ Colls.NameEncrypted => filter.Value.Split(";").Select(x => x as object).Take(1).ToList(), Colls.InfoName => filter.Value.Split(";").Select(x => x as object).ToList(), Colls.NullableString => filter.Value.Split(";").Select(x => x == "null" ? null : (x as object)).ToList(), - _ => throw new ArgumentOutOfRangeException() + _ => filter.Value.Split(";").Select(x => x == "null" ? null : (x as object)).ToList(), }; if (values.Any()) @@ -203,6 +221,7 @@ ComparisonType = filter.Key switch { + Colls.SomeClassList => ComparisonType.Contains, Colls.Name => values.Count > 1 ? ComparisonType.In : ComparisonType.Contains, diff --git a/TestFilters/Components/Pages/TestDirect.razor b/TestFilters/Components/Pages/TestDirect.razor new file mode 100644 index 0000000..21d3bed --- /dev/null +++ b/TestFilters/Components/Pages/TestDirect.razor @@ -0,0 +1,41 @@ +@page "/TestDirect" +@rendermode InteractiveServer + + + + + + +@code { + + void t1() + { + var cl = new HttpClient() + { + BaseAddress = new Uri("http://127.0.0.1/") + }; + + cl.GetAsync("api/test/direct"); + + } + + void t2() + { + var cl = new HttpClient() + { + BaseAddress = new Uri("http://127.0.0.1/") + }; + + cl.GetAsync("api/test/distinct"); + + } + void t3() { + var cl = new HttpClient() + { + BaseAddress = new Uri("http://127.0.0.1/") + }; + + cl.GetAsync("api/test/join"); + + } +} \ No newline at end of file diff --git a/TestFilters/Program.cs b/TestFilters/Program.cs index df0da01..8f594cb 100644 --- a/TestFilters/Program.cs +++ b/TestFilters/Program.cs @@ -24,6 +24,8 @@ builder.Services.AddPandatechCryptoAes256(options => options.Key = key); +builder.Services.AddSwaggerGen(); + builder.Services.AddHttpClient(); var app = builder.Build(); @@ -42,7 +44,8 @@ var db = scope.ServiceProvider.GetRequiredService(); db.Database.EnsureDeleted(); db.Database.EnsureCreated(); -db.Populate(1000); +await db.Populate(1000); +await db.PopulateTest(); app.UseHttpsRedirection(); @@ -56,10 +59,47 @@ app.MapGet("/api/companies", (PostgresContext context, [FromQuery] int page, [FromQuery] int pageSize, [FromQuery] string q) => S.Companies(context, page, pageSize, q)); app.MapGet("/api/companies/distinct/{columnName}", (PostgresContext context, [FromRoute] string columnName, - [FromQuery] string filterString, [FromQuery] int page, [FromQuery] int pageSize) => + [FromQuery] string filterString, [FromQuery] int page, [FromQuery] int pageSize) => S.DistinctColumnValues(context, columnName, filterString, page, pageSize)); + + +app.MapGet("/api/test/distinct", S.DistinctTest); +app.MapGet("/api/test/direct", S.DirectTest); +app.MapGet("/api/test/join", S.JoinTest); + +app.MapGet("/{Name}/{foo}", Bar); + +app.UseSwagger(); +app.MapSwagger(); + app.Run(); +void Bar ([FromQuery] Foo foo) +{ + Console.WriteLine(foo.Name); + Console.WriteLine(foo.page); + Console.WriteLine(foo.pageSize); +} +class Foo: IParsable +{ + public string Name { get; set; } + public int page { get; set; } + public int pageSize { get; set; } + + + public static Foo Parse(string s, IFormatProvider? provider) + { + Console.WriteLine(s); + return default; + } + + public static bool TryParse(string? s, IFormatProvider? provider, out Foo result) + { + Console.WriteLine(s); + result = default; + return false; + } +} namespace TestFilters { @@ -71,25 +111,49 @@ public static async Task> Companies(PostgresContext context, [From { var req = GetDataRequest.FromString(q); - return await context.Companies - .ApplyFilters(req.Filters) - //.ApplyOrdering(req.Order, company => company.Id) + .ApplyFilters(req.Filters, context) + .Include(x => x.SomeClass) + .Include(x => x.SomeClassList) .ApplyOrdering(req.Order) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); } - - public static async Task DistinctColumnValues(PostgresContext context, [FromQuery] string columnName, + + public static async Task DistinctColumnValues(PostgresContext context, + [FromQuery] string columnName, [FromQuery] string filterString, [FromQuery] int page, [FromQuery] int pageSize) { var req = GetDataRequest.FromString(filterString); - var query = context.Companies - .DistinctColumnValues(req.Filters, columnName, pageSize, page); + var query = await context.Companies + .DistinctColumnValuesAsync(req.Filters, columnName, pageSize, page, context); return query; } + + public static async Task DistinctTest(PostgresContext context) + { + var query = await context.As + .Include(x => x.B) + .ThenInclude(x => x.C) + .GroupBy(x => x.B.C) + .Select(x => x.FirstOrDefault()) + .ToListAsync(); + } + + public static async Task JoinTest(PostgresContext context) + { + var query = await context.As + .Select(x => x.B.C) + .Distinct() + .ToListAsync(); + } + + public static async Task DirectTest(PostgresContext context) + { + var query = await context.As.Include(x => x.B).ThenInclude(x => x.C).ToListAsync(); + } } } \ No newline at end of file diff --git a/TestFilters/db/Company.cs b/TestFilters/db/Company.cs index a266ca6..979e88f 100644 --- a/TestFilters/db/Company.cs +++ b/TestFilters/db/Company.cs @@ -15,4 +15,7 @@ public class Company public CType Type { get; set; } public CType[] Types { get; set; } public Info Info { get; set; } = null!; + + public SomeClass? SomeClass { get; set; } + public List SomeClassList { get; set; } } \ No newline at end of file diff --git a/TestFilters/db/CompanyFilter.cs b/TestFilters/db/CompanyFilter.cs index a87c5a6..8d14863 100644 --- a/TestFilters/db/CompanyFilter.cs +++ b/TestFilters/db/CompanyFilter.cs @@ -1,4 +1,7 @@ -using PandaTech.IEnumerableFilters.Attributes; +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore; +using PandaTech.IEnumerableFilters; +using PandaTech.IEnumerableFilters.Attributes; using PandaTech.IEnumerableFilters.Enums; namespace TestFilters.db; @@ -33,4 +36,95 @@ public class CompanyFilter [MappedToProperty(nameof(Company.Info), nameof(Company.Info.Name))] public string InfoName { get; set; } = null!; -} \ No newline at end of file + + [MappedToProperty(nameof(Company.SomeClass), nameof(Company.SomeClass.Name))] + public string? SomeClass { get; set; } = null!; + + + [MappedToProperty(nameof(Company.SomeClass), nameof(Company.SomeClass.NullableString))] + public string? SomeClassN { get; set; } = null!; + + [MappedToProperty(nameof(Company.SomeClass), nameof(Company.SomeClass.NameEncrypted), Encrypted = true)] + public string? SomeClassNn { get; set; } = null!; + + [MappedToProperty(nameof(Company.SomeClassList), ConverterType = typeof(SomeClassConverter))] + public string? SomeClassList { get; set; } = null!; +} + +public class SomeClassConverter : IConverter +{ + public DbContext Context { get; set; } + public string ConvertFrom(SomeClass from) => from.Name; + + public SomeClass ConvertTo(string from) + { + var result = Context.Set().FirstOrDefault(x => x.Name.ToLower() == from.ToLower()); + var a = 1; + return result; + } +} + + +public abstract class FilterRules +{ + + private List _rules = new(); + + private interface IRule; + + + + protected class Rule : IRule + { + public Rule ConvertTo(Expression> converter) + { + return this; + } + + public Rule ConvertFrom(Expression> converter) + { + return this; + } + + public Rule AddDefaultComparisons() + { + return this; + } + + public Rule AddComparison(ComparisonType comparisonType, Func func) + { + return this; + } + }; + + protected Rule RuleFor(string name, Expression> expression) + { + var rule = new Rule(); + _rules.Add(rule); + + return rule; + } + + protected Rule RuleFor(string name, Expression> expression) + { + var rule = new Rule(); + _rules.Add(rule); + + return rule; + } +} + +public class CompanyFilterRules : FilterRules +{ + public CompanyFilterRules() + { + RuleFor("Id", x => x.Id) + .ConvertTo(x => long.Parse(x)) + .ConvertFrom(x => x.ToString()) + .AddDefaultComparisons(); + + RuleFor("Age", x => x.Age) + .AddComparison(ComparisonType.Between, (x, p) => x > p[0] && x < p[1]); + } +} + diff --git a/TestFilters/db/PostgresContext.cs b/TestFilters/db/PostgresContext.cs index cc10780..a625356 100644 --- a/TestFilters/db/PostgresContext.cs +++ b/TestFilters/db/PostgresContext.cs @@ -9,12 +9,25 @@ namespace TestFilters.db; public class PostgresContext(DbContextOptions options, Aes256 aes256) : PostgresDbContext(options) { public virtual DbSet Companies { get; set; } = null!; + public virtual DbSet SomeClasses { get; set; } = null!; + + + public virtual DbSet As { get; set; } = null!; + public virtual DbSet Bs { get; set; } = null!; + public virtual DbSet Cs { get; set; } = null!; protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity() .OwnsOne(c => c.Info, d => { d.ToJson(); }); + modelBuilder.Entity() + .HasMany().WithOne(); + + modelBuilder.Entity().HasOne(x => x.B).WithMany(); + modelBuilder.Entity().HasOne(x => x.C).WithMany(); + + base.OnModelCreating(modelBuilder); } @@ -25,11 +38,25 @@ public async Task Populate(int count) var fake = new Faker() .RuleFor(x => x.Name, f => f.Company.CompanyName()) + .RuleFor(x => x.SomeClass, f => f.Random.Bool() + ? new SomeClass + { + Name = f.Company.CompanyName(), + NameEncrypted = aes256.Encrypt(f.Company.CompanyName()), + NullableString = f.Random.Bool() ? f.Company.CompanyName() : null + } + : null) .RuleFor(x => x.NameEncrypted, (f, e) => aes256.Encrypt(e.Name)) .RuleFor(x => x.Age, f => f.Random.Long(1, 100)) .RuleFor(x => x.IsEnabled, f => f.Random.Bool()) .RuleFor(x => x.Info, f => new Info { Name = f.Company.CompanyName() }) .RuleFor(x => x.NullableString, f => f.Random.Bool() ? f.Company.CompanyName() : null) + .RuleFor(x => x.SomeClassList, faker => new Faker() + .RuleFor(x => x.Name, f => f.Company.CompanyName()) + .RuleFor(x => x.NameEncrypted, (f, e) => aes256.Encrypt(e.Name)) + .RuleFor(x => x.NullableString, f => f.Random.Bool() ? f.Company.CompanyName() : null) + .Generate(faker.Random.Int(1, 10)) + .ToList()) .RuleFor(x => x.Types, f => new[] { f.PickRandom(), @@ -45,4 +72,61 @@ public async Task Populate(int count) await AddRangeAsync(generatedData); await SaveChangesAsync(); } + + public async Task PopulateTest() + { + const int cAmount = 1000; + const int bAmount = 1000; + const int aAmount = 1000; + + var cFaker = new Faker() + .RuleFor(x => x.Name, f => f.Company.CompanyName()); + + Cs.AddRange(cFaker.Generate(cAmount)); + + await SaveChangesAsync(); + + var cs = await Cs.ToListAsync(); + + var bFaker = new Faker() + .RuleFor(x => x.Name, f => f.Company.CompanyName()) + .RuleFor(x => x.C, f => f.PickRandom(cs)); + + Bs.AddRange(bFaker.Generate(bAmount)); + + await SaveChangesAsync(); + + var bs = await Bs.ToListAsync(); + + var aFaker = new Faker() + .RuleFor(x => x.Name, f => f.Company.CompanyName()) + .RuleFor(x => x.B, f => f.PickRandom(bs)); + + As.AddRange(aFaker.Generate(aAmount)); + + await SaveChangesAsync(); + + } +} + +public class A +{ + public int Id { get; set; } + public string Name { get; set; } = null!; + + public B B { get; set; } = null!; + +} + +public class B +{ + public int Id { get; set; } + public string Name { get; set; } = null!; + public C C { get; set; } = null!; +} + +public class C +{ + public int Id { get; set; } + public string Name { get; set; } = null!; } \ No newline at end of file diff --git a/TestFilters/db/SomeClass.cs b/TestFilters/db/SomeClass.cs new file mode 100644 index 0000000..2deb13d --- /dev/null +++ b/TestFilters/db/SomeClass.cs @@ -0,0 +1,9 @@ +namespace TestFilters.db; + +public class SomeClass +{ + public long Id { get; set; } + public string Name { get; set; } = null!; + public string? NullableString { get; set; } + public byte[] NameEncrypted { get; set; } +} \ No newline at end of file
Id Age InfoNameNameName EncryptedIsEnabledTypeTypesNullableString
@coll.ToString()
@r.Id@r.Age@r.Info.Name@r.Name@Aes256.Decrypt(r.NameEncrypted)@r.IsEnabled@r.Type@string.Join(';', r.Types.Select(x => x.ToString())) @r.NullableString@string.Join(';', r.Types.Select(x => x.ToString())) @Aes256.Decrypt(r.NameEncrypted)@r.SomeClass?.Name@r.SomeClass?.NullableString@Aes256.Decrypt(r.SomeClass?.NameEncrypted)@string.Join(';', r.SomeClassList.Select(x => x.Name)) @val