├── .editorconfig ├── .gitattributes ├── .gitignore ├── Issues.md ├── LICENSE ├── LinqSharp.Dev.Shared ├── IEnumerableExtensions - Linq.cs ├── IQueryableExtensions - Linq.cs ├── Infrastructure │ └── Partition.cs ├── LinqSharp.Dev.Shared.projitems ├── LinqSharp.Dev.Shared.shproj ├── ModelCreator.cs ├── RelatedAction.cs ├── RelatedBehavior.cs ├── RelatedInfo.cs ├── ~Array │ └── ArrayExtensions.PartitionBy.cs └── ~EFCore.Dev │ ├── DbSetExtensions.cs │ ├── DeleteWrapper.cs │ ├── UpdateWrapper.cs │ └── WhereWrapper.cs ├── LinqSharp.EFCore.MySql ├── LinqSharp.EFCore.MySql.Compatible │ └── LinqSharp.EFCore.MySql.Compatible.csproj ├── LinqSharp.EFCore.MySql.Shared │ ├── LinqSharp.EFCore.MySql.Shared.projitems │ ├── LinqSharp.EFCore.MySql.Shared.shproj │ └── MySqlBulkCopyEngine.cs └── LinqSharp.EFCore.MySql │ └── LinqSharp.EFCore.MySql.csproj ├── LinqSharp.EFCore.SqlServer ├── LinqSharp.EFCore.SqlServer.Compatible │ └── LinqSharp.EFCore.SqlServer.Compatible.csproj ├── LinqSharp.EFCore.SqlServer.Shared │ ├── LinqSharp.EFCore.SqlServer.Shared.projitems │ ├── LinqSharp.EFCore.SqlServer.Shared.shproj │ └── SqlServerBulkCopyEngine.cs └── LinqSharp.EFCore.SqlServer │ └── LinqSharp.EFCore.SqlServer.csproj ├── LinqSharp.EFCore.Test ├── DbCreators │ ├── DbCreator.MySql │ │ ├── ApplicationDbContextFactory.cs │ │ ├── DbCreator.MySql.csproj │ │ └── Migrations │ │ │ ├── 20241016094721_202410161747.Designer.cs │ │ │ ├── 20241016094721_202410161747.cs │ │ │ ├── 20250324074245_202503241542.Designer.cs │ │ │ ├── 20250324074245_202503241542.cs │ │ │ ├── 20250331071139_202503311510.Designer.cs │ │ │ ├── 20250331071139_202503311510.cs │ │ │ └── ApplicationDbContextModelSnapshot.cs │ ├── DbCreator.PostgreSQL │ │ ├── ApplicationDbContextFactory.cs │ │ ├── DbCreator.PostgreSQL.csproj │ │ └── Migrations │ │ │ ├── 20241016094723_202410161747.Designer.cs │ │ │ ├── 20241016094723_202410161747.cs │ │ │ ├── 20250324074430_202503241542.Designer.cs │ │ │ ├── 20250324074430_202503241542.cs │ │ │ ├── 20250331071142_202503311510.Designer.cs │ │ │ ├── 20250331071142_202503311510.cs │ │ │ └── ApplicationDbContextModelSnapshot.cs │ ├── DbCreator.SqlServer │ │ ├── ApplicationDbContextFactory.cs │ │ ├── DbCreator.SqlServer.csproj │ │ └── Migrations │ │ │ ├── 20241016094725_202410161747.Designer.cs │ │ │ ├── 20241016094725_202410161747.cs │ │ │ ├── 20250324074448_202503241542.Designer.cs │ │ │ ├── 20250324074448_202503241542.cs │ │ │ ├── 20250331071146_202503311510.Designer.cs │ │ │ ├── 20250331071146_202503311510.cs │ │ │ └── ApplicationDbContextModelSnapshot.cs │ └── DbCreator │ │ ├── DbCreator.projitems │ │ ├── DbCreator.shproj │ │ └── Program.cs ├── LinqSharp.EFCore.Test - EF6.0 │ └── LinqSharp.EFCore.Test - EF6.0.csproj ├── LinqSharp.EFCore.Test - EF7.0 │ └── LinqSharp.EFCore.Test - EF7.0.csproj ├── LinqSharp.EFCore.Test - EF8.0 │ └── LinqSharp.EFCore.Test - EF8.0.csproj ├── LinqSharp.EFCore.Test.Data.Shared │ ├── Data │ │ ├── AppRegistryEntity.cs │ │ ├── ApplicationDbContext.cs │ │ ├── ApplicationDbScope.cs │ │ ├── AuditLevel.cs │ │ ├── AuditRoot.cs │ │ ├── AuditValue.cs │ │ ├── AutoModel.cs │ │ ├── BulkTestModel.cs │ │ ├── CPKeyModel.cs │ │ ├── Client.cs │ │ ├── ConcurrencyModel.cs │ │ ├── DbRowNumber.cs │ │ ├── EntityMonitorModel.cs │ │ ├── FacadeModel.cs │ │ ├── LS_Index.cs │ │ ├── LS_Name.cs │ │ ├── LS_Provider.cs │ │ ├── RowLockModel.cs │ │ ├── SimpleModel.cs │ │ ├── SimpleRow.cs │ │ ├── YearMonthModel.cs │ │ ├── Zipper.cs │ │ └── ZipperModel.cs │ ├── DbFuncProviders │ │ └── DbYearMonthNumber.cs │ ├── LinqSharp.EFCore.Test.Data.Shared.projitems │ ├── LinqSharp.EFCore.Test.Data.Shared.shproj │ └── Models │ │ └── NameModel.cs └── LinqSharp.EFCore.Test.Shared │ ├── !DatabaseDepTests │ ├── MutilContext.cs │ ├── MutilContextContainer.cs │ ├── MySqlTests.cs │ ├── SqlServerTests.cs │ └── TestDatabases.cs │ ├── !Support │ └── EFVersion.cs │ ├── !extern │ └── ~Dawnx │ │ └── RegexUtility.cs │ ├── AddOrUpdateTests.cs │ ├── AgentQueryTests.cs │ ├── AuditorTests.cs │ ├── AutoTests.cs │ ├── BulkTests.cs │ ├── CacheableTests.cs │ ├── ChunkTests.cs │ ├── Comparers │ └── SequenceComparerTests.cs │ ├── CompoundQueryTests.cs │ ├── ConcurrencyTests.cs │ ├── DbContextExtensionsTests.cs │ ├── DbFunctionTests.cs │ ├── DbYearMonthNumberTests.cs │ ├── ExpressionExtensionsTests.cs │ ├── FacadeTests.cs │ ├── FilterTests.cs │ ├── IEntityTests.cs │ ├── IEnumerableExtensionsTests.cs │ ├── IndexByTests.cs │ ├── IndexingTests.cs │ ├── JoinTests.cs │ ├── LinqSharp.EFCore.Test.Shared.projitems │ ├── LinqSharp.EFCore.Test.Shared.shproj │ ├── NumericTests.cs │ ├── PagedEnumerableTests.cs │ ├── PartitionTests.cs │ ├── ProviderNameTests.cs │ ├── ProviderTests.cs │ ├── QSum_And_QAverageTests.cs │ ├── RowLockTests.cs │ ├── SameOrDefaultTests.cs │ ├── SearchTests.cs │ ├── SelectAnyTests.cs │ ├── SelectXTests.cs │ ├── SorterTests.cs │ ├── ToSqlTests.cs │ ├── UpdateLockTests.cs │ ├── ZipperTests.cs │ └── extern │ ├── Concurrency.cs │ ├── TestId.cs │ ├── TestReport.cs │ └── TestResult.cs ├── LinqSharp.EFCore ├── LinqSharp.EFCore - EF2.1 │ └── LinqSharp.EFCore - EF2.1.csproj ├── LinqSharp.EFCore - EF3.1 │ └── LinqSharp.EFCore - EF3.1.csproj ├── LinqSharp.EFCore - EF5.0 │ └── LinqSharp.EFCore - EF5.0.csproj ├── LinqSharp.EFCore - EF6.0 │ └── LinqSharp.EFCore - EF6.0.csproj ├── LinqSharp.EFCore - EF7.0 │ └── LinqSharp.EFCore - EF7.0.csproj ├── LinqSharp.EFCore - EF8.0 │ └── LinqSharp.EFCore - EF8.0.csproj ├── LinqSharp.EFCore.Abstractions │ ├── BulkCopyEngine.cs │ └── LinqSharp.EFCore.Abstractions.csproj ├── LinqSharp.EFCore.Core │ ├── Annotations │ │ ├── AutoAttribute.cs │ │ ├── AutoCondensedAttribute.cs │ │ ├── AutoCreatedByAttribute.cs │ │ ├── AutoCreationTimeAttribute.cs │ │ ├── AutoLastWriteTimeAttribute.cs │ │ ├── AutoLowerAttribute.cs │ │ ├── AutoMonthOnlyAttribute.cs │ │ ├── AutoTrimAttribute.cs │ │ ├── AutoUpdatedByAttribute.cs │ │ ├── AutoUpperAttribute.cs │ │ ├── CPKeyAttribute.cs │ │ ├── ConcurrencyPolicyAttribute.cs │ │ ├── ConcurrencyResolvableAttribute.cs │ │ ├── ConcurrencyResolvingMode.cs │ │ ├── IndexFieldAttribute.cs │ │ ├── NotAcceptableAttribute.cs │ │ ├── Params │ │ │ ├── IAutoParam.cs │ │ │ ├── TimestampParam.cs │ │ │ └── UserParam.cs │ │ ├── RelatedAttribute.cs │ │ ├── RowLockAttribute.cs │ │ └── SpecialAutoAttribute.cs │ ├── AutoMode.cs │ ├── AutoState.cs │ ├── Design │ │ ├── EntityAuditAttribute.cs │ │ ├── IConcurrencyResolvable.cs │ │ ├── IUserTraceable.cs │ │ └── ViewAttribute.cs │ ├── EntityAnnotation.cs │ ├── LinqSharp.EFCore.Core.csproj │ ├── ProviderName.cs │ └── Scopes │ │ └── UnsafeQueryScope.cs └── LinqSharp.EFCore.Shared │ ├── !Extensions │ ├── DbContextExtensions.cs │ ├── DbSetExtensions.AddOrUpdate.cs │ ├── DbSetExtensions.cs │ ├── IEntityExtensions.cs │ ├── IIncludableExtensions.cs │ ├── IQueryableExtensions.Random.cs │ ├── IQueryableExtensions.cs │ └── ModelBuilderExtensions.cs │ ├── Agent │ ├── KeyValueAgent.cs │ ├── KeyValueAgentProxy.cs │ └── ZipperAgent.cs │ ├── AuditPredictor.cs │ ├── Design │ ├── ICacheable.cs │ ├── IEntity.cs │ ├── IEntityAuditor.cs │ └── IZipperEntity.cs │ ├── Entities │ ├── FieldChangeInfo.cs │ ├── KeyValueEntity.cs │ └── RowChangeInfo.cs │ ├── EntityAudit.cs │ ├── Facades │ └── EntityMonitoringFacade.cs │ ├── Infrastructure │ ├── Facade.cs │ ├── IFacade.cs │ ├── IFacadeState.cs │ ├── SqlIdentifiers.cs │ └── Transaction.cs │ ├── LinqSharp.EFCore.Shared.projitems │ ├── LinqSharp.EFCore.Shared.shproj │ ├── LinqSharpEF.cs │ ├── LinqSharpEFRegister.cs │ ├── Navigation │ ├── IIncludable.cs │ ├── IncludeNavigation.cs │ └── QueryTarget.cs │ ├── PropIndex.cs │ ├── Providers │ ├── JsonProvider.cs │ ├── ProviderAttribute.cs │ └── SpecialProviderAttribute.cs │ ├── Query │ ├── SqlTranslator.cs │ ├── Translator.cs │ └── UpdateOptions.cs │ ├── QueryDef.cs │ ├── Scopes │ ├── AgentQueryScope.cs │ ├── CompoundQueryScope.cs │ ├── IAutoModeScope.cs │ ├── RowLockScope.cs │ ├── TimestampScope.cs │ ├── UserTraceScope.cs │ └── ZipperQueryScope.cs │ └── Translators │ ├── DbConcat.cs │ ├── DbDateTime.cs │ ├── DbDouble.cs │ └── DbRandom.cs ├── LinqSharp.lutconfig ├── LinqSharp.png ├── LinqSharp.sln ├── LinqSharp ├── !Extensions │ ├── !IEnumerable │ │ ├── IEnumerableExtensions.AllSame.cs │ │ ├── IEnumerableExtensions.Average.cs │ │ ├── IEnumerableExtensions.AverageOrDefault.cs │ │ ├── IEnumerableExtensions.DistinctBy.cs │ │ ├── IEnumerableExtensions.Filter.cs │ │ ├── IEnumerableExtensions.GroupByCount.cs │ │ ├── IEnumerableExtensions.IndexBy.cs │ │ ├── IEnumerableExtensions.Join.cs │ │ ├── IEnumerableExtensions.Linq.cs │ │ ├── IEnumerableExtensions.MaxOrDefault.cs │ │ ├── IEnumerableExtensions.MinOrDefault.cs │ │ ├── IEnumerableExtensions.Order.cs │ │ ├── IEnumerableExtensions.OrderByCase.cs │ │ ├── IEnumerableExtensions.Pad.cs │ │ ├── IEnumerableExtensions.Page.cs │ │ ├── IEnumerableExtensions.Random.cs │ │ ├── IEnumerableExtensions.Repeat.cs │ │ ├── IEnumerableExtensions.Same.cs │ │ ├── IEnumerableExtensions.SameOrDefault.cs │ │ ├── IEnumerableExtensions.Search.cs │ │ ├── IEnumerableExtensions.SelectMore.cs │ │ ├── IEnumerableExtensions.SelectUntil.cs │ │ ├── IEnumerableExtensions.SelectWhile.cs │ │ ├── IEnumerableExtensions.Sum.cs │ │ ├── IEnumerableExtensions.Tile.cs │ │ ├── IEnumerableExtensions.WhereMax.cs │ │ ├── IEnumerableExtensions.WhereMin.cs │ │ └── IEnumerableExtensions.cs │ ├── !IQueryable │ │ ├── IQueryableExtensions.AverageOrDefault.cs │ │ ├── IQueryableExtensions.Filter.cs │ │ ├── IQueryableExtensions.MaxOrDefault.cs │ │ ├── IQueryableExtensions.MinOrDefault.cs │ │ ├── IQueryableExtensions.Order.cs │ │ ├── IQueryableExtensions.OrderByCase.cs │ │ ├── IQueryableExtensions.Page.cs │ │ ├── IQueryableExtensions.Search.cs │ │ ├── IQueryableExtensions.WhereMax.cs │ │ ├── IQueryableExtensions.WhereMin.cs │ │ └── IQueryableExtensions.cs │ ├── EnumExtensions.cs │ └── ExpressionExtensions.cs ├── !Internal │ ├── MethodAccessor.Enumerable.cs │ ├── MethodAccessor.Enumerable.tt │ ├── MethodAccessor.Object.cs │ ├── MethodAccessor.Object.tt │ ├── MethodAccessor.String.cs │ └── MethodAccessor.String.tt ├── Comparers │ ├── ExactEqualityComparer.cs │ └── SequenceComparer.cs ├── Design │ ├── !FieldFilter │ │ ├── ICoFieldFilter.cs │ │ └── IFieldFilter.cs │ ├── !Filter │ │ ├── ILocalFilter.cs │ │ └── IQueryFilter.cs │ ├── !Sorter │ │ ├── ICoLocalSorter.cs │ │ ├── ICoQuerySorter.cs │ │ ├── ILocalSorter.cs │ │ ├── IQuerySorter.cs │ │ ├── LocalSortRule.cs │ │ └── QuerySortRule.cs │ ├── ISummable.cs │ ├── QueryExpression.cs │ └── QueryHelper.cs ├── Filters │ ├── DateOnlyRangeFilter.cs │ ├── DateTimeRangeFilter.cs │ └── SearchFilter.cs ├── LinqSharp.csproj ├── PadDirection.cs ├── Query │ ├── EnumerablePage.cs │ ├── IEnumerablePage.cs │ ├── IIndexing.cs │ ├── IJoinResult.cs │ ├── IQueryablePage.cs │ ├── IUniqueIndexing.cs │ ├── Indexing.cs │ ├── JoinResult.cs │ ├── QueryablePage.cs │ └── UniqueIndexing.cs ├── SearchMode.cs ├── SearchSelector.cs ├── Strategies │ ├── IQueryStrategy.cs │ ├── OrderByCaseStrategy.cs │ ├── QueryAfterStrategy.cs │ ├── QueryBeforeStrategy.cs │ └── QueryStringStrategy.cs └── Utils │ ├── DataAnnotation.cs │ ├── ExpressionRebinder.cs │ ├── ExpressionRewriter.cs │ ├── Property.cs │ └── PropertyExplorer.cs ├── README.cn.md ├── README.md ├── docs ├── cn │ ├── ef-agent-query.md │ ├── ef-calc-functions.md │ ├── ef-compound-query.md │ ├── ef-concurrency-resolving.md │ ├── ef-data-annotations-1.md │ ├── ef-data-annotations-2.md │ ├── ef-direct-handling.md │ ├── ef-translator.md │ ├── filter.md │ └── query.md └── images │ ├── compound-query.png │ ├── employee-tree.png │ ├── select-more.png │ ├── select-until.png │ └── select-while.png ├── dotnet-orm ├── Commands │ └── DbStructureCommand.cs ├── DataAnnotationEx.cs ├── DbStructureBuilder.cs ├── DbTable.cs ├── DbTableField.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── dotnet-orm.csproj └── dotnet-orm.xml └── push.cmd /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # CS1591: Missing XML comment for publicly visible type or member 4 | dotnet_diagnostic.CS1591.severity = silent 5 | 6 | [*.{csproj,xml}] 7 | indent_size = 2 8 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/IEnumerableExtensions - Linq.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqSharp.Dev; 9 | 10 | public static partial class IEnumerableExtensions 11 | { 12 | public static IEnumerable WhereNot(this IEnumerable @this, Expression> predicate) 13 | { 14 | return @this.Where(Expression.Lambda>(Expression.Not(predicate.Body), predicate.Parameters).Compile()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/IQueryableExtensions - Linq.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Comparers; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp.Dev; 10 | 11 | public static partial class IQueryableExtensions 12 | { 13 | public static IQueryable WhereNot(this IQueryable @this, Expression> predicate) 14 | { 15 | return @this.Where(Expression.Lambda>(Expression.Not(predicate.Body), predicate.Parameters)); 16 | } 17 | 18 | /// 19 | /// Produces the set union of two sequences by using a specified properties. 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | public static IQueryable UnionByValue(this IQueryable first, IQueryable second, Expression> compare) 27 | { 28 | return Queryable.Union(first, second, new ExactEqualityComparer(compare)); 29 | } 30 | 31 | /// 32 | /// Produces the set intersection of two sequences by using the specified properties to compare values. 33 | /// 34 | /// 35 | /// 36 | /// 37 | /// 38 | /// 39 | public static IQueryable IntersectByValue(this IQueryable first, IQueryable second, Expression> compare) 40 | { 41 | return Queryable.Intersect(first, second, new ExactEqualityComparer(compare)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/Infrastructure/Partition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace LinqSharp.Infrastructure; 4 | 5 | public class Partition : IEnumerable 6 | { 7 | public TEntity[] Source { get; } 8 | public int Start { get; } 9 | public int End { get; } 10 | 11 | public Partition(TEntity[] source, int start, int end) 12 | { 13 | Source = source; 14 | Start = start; 15 | End = end; 16 | } 17 | 18 | public IEnumerable GetEnumerable() 19 | { 20 | if (Start > -1) 21 | { 22 | for (int i = Start; i <= End; i++) 23 | { 24 | yield return Source[i]; 25 | } 26 | } 27 | } 28 | 29 | public IEnumerator GetEnumerator() 30 | { 31 | return GetEnumerable().GetEnumerator(); 32 | } 33 | 34 | IEnumerator IEnumerable.GetEnumerator() 35 | { 36 | return GetEnumerator(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/LinqSharp.Dev.Shared.projitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | cdcca828-bd26-4090-9484-67762143932f 7 | 8 | 9 | LinqSharp.Dev.Shared 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/LinqSharp.Dev.Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | cdcca828-bd26-4090-9484-67762143932f 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/RelatedAction.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore; 2 | 3 | public enum RelatedAction 4 | { 5 | None, 6 | OneToOne, 7 | OneToMany, 8 | ManyToOne, 9 | } 10 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/RelatedBehavior.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore; 2 | 3 | public enum RelatedBehavior 4 | { 5 | ClientSetNull, 6 | 7 | Restrict, 8 | 9 | SetNull, 10 | 11 | Cascade 12 | } 13 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/RelatedInfo.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore; 2 | 3 | public class RelatedInfo 4 | { 5 | public RelatedAction Action { get; set; } 6 | public string Related { get; set; } 7 | public string Navigation { get; set; } 8 | public RelatedBehavior Behavior { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/~Array/ArrayExtensions.PartitionBy.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.Infrastructure; 2 | using NStandard; 3 | 4 | namespace LinqSharp; 5 | 6 | public static partial class ArrayExtensions 7 | { 8 | public static Partition[] PartitionBy(this TEntity[] @this, params Func[] predicates) 9 | { 10 | var index = 0; 11 | var partitions = new Partition[predicates.Length]; 12 | 13 | for (int i = 0; i < predicates.Length; i++) 14 | { 15 | if (index == -1) 16 | { 17 | partitions[i] = new Partition(@this, -1, -1); 18 | continue; 19 | } 20 | 21 | var predicate = predicates[i]; 22 | var start = @this.IndexOf(predicate, index); 23 | index = @this.IndexOf(x => !predicate(x), start + 1); 24 | 25 | if (start == -1) 26 | { 27 | index = -1; 28 | partitions[i] = new Partition(@this, -1, -1); 29 | } 30 | else 31 | { 32 | var end = index == -1 ? @this.Length - 1 : index - 1; 33 | partitions[i] = new Partition(@this, start, end); 34 | } 35 | } 36 | 37 | return partitions; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/~EFCore.Dev/DbSetExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | using System.ComponentModel; 8 | using System.Linq.Expressions; 9 | 10 | namespace LinqSharp.EFCore.Dev; 11 | 12 | [EditorBrowsable(EditorBrowsableState.Never)] 13 | public static class DbSetExtensions 14 | { 15 | [Obsolete("The API is part of the experimental feature and may be modified or removed in the future.")] 16 | public static UpdateWrapper TryUpdate(this DbSet @this, Expression> expression) where TEntity : class 17 | { 18 | return new UpdateWrapper(new WhereWrapper(@this, expression)); 19 | } 20 | 21 | [Obsolete("The API is part of the experimental feature and may be modified or removed in the future.")] 22 | public static DeleteWrapper TryDelete(this DbSet @this, Expression> expression) where TEntity : class 23 | { 24 | return new DeleteWrapper(new WhereWrapper(@this, expression)); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/~EFCore.Dev/DeleteWrapper.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | namespace LinqSharp.EFCore.Dev; 9 | 10 | public class DeleteWrapper 11 | where TEntity : class 12 | { 13 | public WhereWrapper WhereWrapper { get; } 14 | 15 | public DeleteWrapper(WhereWrapper whereWrapper) 16 | { 17 | WhereWrapper = whereWrapper; 18 | } 19 | 20 | public string ToSql() 21 | { 22 | return $"DELETE FROM {WhereWrapper.TableName} WHERE {WhereWrapper.WhereString};"; 23 | } 24 | 25 | #if EFCORE3_1_OR_GREATER 26 | public int Save() => WhereWrapper.DbContext.Database.ExecuteSqlRaw(ToSql()); 27 | #else 28 | public int Save() => WhereWrapper.DbContext.Database.ExecuteSqlCommand(ToSql()); 29 | #endif 30 | } 31 | -------------------------------------------------------------------------------- /LinqSharp.Dev.Shared/~EFCore.Dev/WhereWrapper.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | using System.Linq.Expressions; 8 | using System.Text.RegularExpressions; 9 | 10 | namespace LinqSharp.EFCore.Dev; 11 | 12 | public class WhereWrapper 13 | where TEntity : class 14 | { 15 | public DbContext DbContext { get; } 16 | public string TableName { get; } 17 | public string TableAlias { get; } 18 | public string WhereString { get; } 19 | public string ReferenceTagA { get; } 20 | public string ReferenceTagB { get; } 21 | 22 | public WhereWrapper(DbSet dbSet, Expression> expression) 23 | { 24 | DbContext = dbSet.GetDbContext(); 25 | 26 | var sql = dbSet.Where(expression).ToQueryString(); 27 | var regex = new Regex(@"FROM\s+((.).+?(.))\s+AS\s+([^\s|\r|;]+)(\s+WHERE\s+([^;]+))?", RegexOptions.Singleline); 28 | var match = regex.Match(sql); 29 | 30 | TableName = match.Groups[1].Value; 31 | ReferenceTagA = match.Groups[2].Value; 32 | ReferenceTagB = match.Groups[3].Value; 33 | TableAlias = match.Groups[4].Value; 34 | 35 | if (match.Groups[5].Success) 36 | WhereString = match.Groups[6].Value.Replace(TableAlias, TableName); 37 | else WhereString = "1=1"; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.MySql/LinqSharp.EFCore.MySql.Shared/LinqSharp.EFCore.MySql.Shared.projitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | 3fba9dc7-be32-4755-82c2-e5200fc05b61 7 | 8 | 9 | LinqSharp.EFCore.MySql.Shared 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.MySql/LinqSharp.EFCore.MySql.Shared/LinqSharp.EFCore.MySql.Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3fba9dc7-be32-4755-82c2-e5200fc05b61 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.MySql/LinqSharp.EFCore.MySql/LinqSharp.EFCore.MySql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net5.0;net6.0;net7.0 6 | 7 | preview 8 | LinqSharp.EFCore.MySql 9 | zmjack 10 | LinqSharp.EFCore.MySql 11 | LICENSE 12 | LinqSharp.png 13 | git 14 | https://github.com/zmjack/LinqSharp 15 | https://github.com/zmjack/LinqSharp 16 | Linq EFCore MySql 17 | Copyright © linqsharp.net 2020 18 | 7.0.6 19 | true 20 | Expansion pack, including batch import function, etc. 21 | 22 | 23 | 24 | DEBUG;TRACE 25 | 26 | 27 | 28 | none 29 | false 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | True 39 | 40 | 41 | 42 | True 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.SqlServer/LinqSharp.EFCore.SqlServer.Shared/LinqSharp.EFCore.SqlServer.Shared.projitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | 2b434169-a544-40cb-89fd-d275466f5aa1 7 | 8 | 9 | LinqSharp.EFCore.SqlServer.Shared 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.SqlServer/LinqSharp.EFCore.SqlServer.Shared/LinqSharp.EFCore.SqlServer.Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2b434169-a544-40cb-89fd-d275466f5aa1 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.MySql/ApplicationDbContextFactory.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using Microsoft.EntityFrameworkCore.Design; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | 5 | namespace DbCreator; 6 | 7 | public class ApplicationDbContextFactory : IDesignTimeDbContextFactory 8 | { 9 | public ApplicationDbContext CreateDbContext(string[] args) 10 | { 11 | return UseDefault(b => b.MigrationsAssembly("DbCreator.MySql")); 12 | } 13 | 14 | public static ApplicationDbContext UseDefault(Action? mySqlOptionsAction = null) 15 | { 16 | return ApplicationDbContext.UseMySql(mySqlOptionsAction); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.MySql/DbCreator.MySql.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | DbCreator 7 | enable 8 | enable 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.MySql/Migrations/20250324074245_202503241542.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.Migrations 6 | { 7 | /// 8 | public partial class _202503241542 : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.CreateTable( 14 | name: "ZipperModels", 15 | columns: table => new 16 | { 17 | Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), 18 | KeyName = table.Column(type: "varchar(255)", maxLength: 255, nullable: true) 19 | .Annotation("MySql:CharSet", "utf8mb4"), 20 | Price = table.Column(type: "decimal(65,30)", nullable: true), 21 | ZipperStart = table.Column(type: "date", nullable: false), 22 | ZipperEnd = table.Column(type: "date", nullable: false) 23 | }, 24 | constraints: table => 25 | { 26 | table.PrimaryKey("PK_ZipperModels", x => x.Id); 27 | }) 28 | .Annotation("MySql:CharSet", "utf8mb4"); 29 | } 30 | 31 | /// 32 | protected override void Down(MigrationBuilder migrationBuilder) 33 | { 34 | migrationBuilder.DropTable( 35 | name: "ZipperModels"); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.MySql/Migrations/20250331071139_202503311510.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.Migrations 6 | { 7 | /// 8 | public partial class _202503311510 : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.AlterColumn( 14 | name: "ZipperStart", 15 | table: "ZipperModels", 16 | type: "datetime(6)", 17 | nullable: false, 18 | oldClrType: typeof(DateOnly), 19 | oldType: "date"); 20 | 21 | migrationBuilder.AlterColumn( 22 | name: "ZipperEnd", 23 | table: "ZipperModels", 24 | type: "datetime(6)", 25 | nullable: false, 26 | oldClrType: typeof(DateOnly), 27 | oldType: "date"); 28 | } 29 | 30 | /// 31 | protected override void Down(MigrationBuilder migrationBuilder) 32 | { 33 | migrationBuilder.AlterColumn( 34 | name: "ZipperStart", 35 | table: "ZipperModels", 36 | type: "date", 37 | nullable: false, 38 | oldClrType: typeof(DateTime), 39 | oldType: "datetime(6)"); 40 | 41 | migrationBuilder.AlterColumn( 42 | name: "ZipperEnd", 43 | table: "ZipperModels", 44 | type: "date", 45 | nullable: false, 46 | oldClrType: typeof(DateTime), 47 | oldType: "datetime(6)"); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.PostgreSQL/ApplicationDbContextFactory.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using Microsoft.EntityFrameworkCore.Design; 3 | using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure; 4 | 5 | namespace DbCreator; 6 | 7 | public class ApplicationDbContextFactory : IDesignTimeDbContextFactory 8 | { 9 | public ApplicationDbContext CreateDbContext(string[] args) 10 | { 11 | return UseDefault(b => b.MigrationsAssembly("DbCreator.PostgreSQL")); 12 | } 13 | 14 | public static ApplicationDbContext UseDefault(Action? action = null) 15 | { 16 | return ApplicationDbContext.UsePostgreSQL(action); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.PostgreSQL/DbCreator.PostgreSQL.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | DbCreator 7 | enable 8 | enable 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.PostgreSQL/Migrations/20250324074430_202503241542.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.Migrations 6 | { 7 | /// 8 | public partial class _202503241542 : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.CreateTable( 14 | name: "ZipperModels", 15 | columns: table => new 16 | { 17 | Id = table.Column(type: "uuid", nullable: false), 18 | KeyName = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), 19 | Price = table.Column(type: "numeric", nullable: true), 20 | ZipperStart = table.Column(type: "date", nullable: false), 21 | ZipperEnd = table.Column(type: "date", nullable: false) 22 | }, 23 | constraints: table => 24 | { 25 | table.PrimaryKey("PK_ZipperModels", x => x.Id); 26 | }); 27 | } 28 | 29 | /// 30 | protected override void Down(MigrationBuilder migrationBuilder) 31 | { 32 | migrationBuilder.DropTable( 33 | name: "ZipperModels"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.PostgreSQL/Migrations/20250331071142_202503311510.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.Migrations 6 | { 7 | /// 8 | public partial class _202503311510 : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.AlterColumn( 14 | name: "ZipperStart", 15 | table: "ZipperModels", 16 | type: "timestamp with time zone", 17 | nullable: false, 18 | oldClrType: typeof(DateOnly), 19 | oldType: "date"); 20 | 21 | migrationBuilder.AlterColumn( 22 | name: "ZipperEnd", 23 | table: "ZipperModels", 24 | type: "timestamp with time zone", 25 | nullable: false, 26 | oldClrType: typeof(DateOnly), 27 | oldType: "date"); 28 | } 29 | 30 | /// 31 | protected override void Down(MigrationBuilder migrationBuilder) 32 | { 33 | migrationBuilder.AlterColumn( 34 | name: "ZipperStart", 35 | table: "ZipperModels", 36 | type: "date", 37 | nullable: false, 38 | oldClrType: typeof(DateTime), 39 | oldType: "timestamp with time zone"); 40 | 41 | migrationBuilder.AlterColumn( 42 | name: "ZipperEnd", 43 | table: "ZipperModels", 44 | type: "date", 45 | nullable: false, 46 | oldClrType: typeof(DateTime), 47 | oldType: "timestamp with time zone"); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.SqlServer/ApplicationDbContextFactory.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using Microsoft.EntityFrameworkCore.Design; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | 5 | namespace DbCreator; 6 | 7 | public class ApplicationDbContextFactory : IDesignTimeDbContextFactory 8 | { 9 | public ApplicationDbContext CreateDbContext(string[] args) 10 | { 11 | return UseDefault(b => b.MigrationsAssembly("DbCreator.SqlServer")); 12 | } 13 | 14 | public static ApplicationDbContext UseDefault(Action? action = null) 15 | { 16 | return ApplicationDbContext.UseSqlServer(action); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.SqlServer/DbCreator.SqlServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | DbCreator 7 | enable 8 | enable 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator.SqlServer/Migrations/20250331071146_202503311510.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.Migrations 6 | { 7 | /// 8 | public partial class _202503311510 : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.AlterColumn( 14 | name: "ZipperStart", 15 | table: "ZipperModels", 16 | type: "datetime2", 17 | nullable: false, 18 | oldClrType: typeof(DateOnly), 19 | oldType: "date"); 20 | 21 | migrationBuilder.AlterColumn( 22 | name: "ZipperEnd", 23 | table: "ZipperModels", 24 | type: "datetime2", 25 | nullable: false, 26 | oldClrType: typeof(DateOnly), 27 | oldType: "date"); 28 | } 29 | 30 | /// 31 | protected override void Down(MigrationBuilder migrationBuilder) 32 | { 33 | migrationBuilder.AlterColumn( 34 | name: "ZipperStart", 35 | table: "ZipperModels", 36 | type: "date", 37 | nullable: false, 38 | oldClrType: typeof(DateTime), 39 | oldType: "datetime2"); 40 | 41 | migrationBuilder.AlterColumn( 42 | name: "ZipperEnd", 43 | table: "ZipperModels", 44 | type: "date", 45 | nullable: false, 46 | oldClrType: typeof(DateTime), 47 | oldType: "datetime2"); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator/DbCreator.projitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | 63969751-f7c1-482b-976b-e8e7e807255b 7 | 8 | 9 | DbCreator 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator/DbCreator.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 63969751-f7c1-482b-976b-e8e7e807255b 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/DbCreators/DbCreator/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Northwnd; 3 | 4 | namespace DbCreator; 5 | 6 | internal class Program 7 | { 8 | internal static void Main(string[] args) 9 | { 10 | var memoryContext = new NorthwndMemoryContext(); 11 | using (var context = ApplicationDbContextFactory.UseDefault()) 12 | { 13 | context.Database.Migrate(); 14 | if (!context.Regions.Any()) 15 | { 16 | context.InitializeNorthwnd(memoryContext); 17 | } 18 | } 19 | 20 | Console.WriteLine("Complete."); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/AppRegistryEntity.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Agent; 2 | using LinqSharp.EFCore.Entities; 3 | 4 | namespace LinqSharp.EFCore.Data.Test; 5 | 6 | public class AppRegistryEntity : KeyValueEntity { } 7 | public class AppRegistry : KeyValueAgent 8 | { 9 | public virtual string Theme { get; set; } = "Default"; 10 | public virtual string Color { get; set; } 11 | 12 | public virtual int Volume { get; set; } 13 | public virtual DateTime? LoginTime { get; set; } 14 | 15 | public virtual bool Lock { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/ApplicationDbScope.cs: -------------------------------------------------------------------------------- 1 | #if !MYSQL_COMPATIBLE 2 | using MySqlConnector; 3 | #else 4 | using MySql.Data.MySqlClient; 5 | #endif 6 | using SQLib; 7 | 8 | namespace LinqSharp.EFCore.Data.Test; 9 | 10 | public class ApplicationDbScope : SqlScope 11 | { 12 | public const string CONNECT_STRING = "server=127.0.0.1;port=43306;user=root;pwd=root;database=LinqSharpTest"; 13 | public static ApplicationDbScope UseDefault() => new(new MySqlConnection(CONNECT_STRING)); 14 | 15 | public ApplicationDbScope(MySqlConnection model) : base(model) { } 16 | } 17 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/AuditLevel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | 6 | namespace LinqSharp.EFCore.Data.Test; 7 | 8 | [EntityAudit(typeof(AuditLevelAudit))] 9 | public class AuditLevel 10 | { 11 | [Key] 12 | public Guid Id { get; set; } 13 | 14 | [ForeignKey(nameof(RootLink))] 15 | public Guid Root { get; set; } 16 | 17 | [ConcurrencyCheck] 18 | public int ValueCount { get; set; } 19 | 20 | public AuditRoot RootLink { get; set; } 21 | 22 | public virtual ICollection Values { get; set; } 23 | } 24 | 25 | public class AuditLevelAudit : IEntityAuditor 26 | { 27 | public void BeforeAudit(ApplicationDbContext context, EntityAudit[] audits) 28 | { 29 | foreach (var audit in audits) 30 | { 31 | if (audit.State == EntityState.Deleted) 32 | { 33 | var values = context.AuditValues.Where(x => x.Level == audit.Current.Id); 34 | context.AuditValues.RemoveRange(values); 35 | } 36 | } 37 | } 38 | 39 | public void OnAudited(ApplicationDbContext context, AuditPredictor predictor) 40 | { 41 | } 42 | 43 | public void OnAuditing(ApplicationDbContext context, EntityAudit[] audits) 44 | { 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/AuditRoot.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace LinqSharp.EFCore.Data.Test; 6 | 7 | [EntityAudit(typeof(AuditRootAudit))] 8 | public class AuditRoot 9 | { 10 | [Key] 11 | public Guid Id { get; set; } 12 | 13 | [ConcurrencyCheck] 14 | public int TotalQuantity { get; set; } 15 | 16 | public int LimitQuantity { get; set; } 17 | 18 | [Timestamp] 19 | public DateTime RowVersion { get; set; } 20 | 21 | public virtual ICollection Levels { get; set; } 22 | } 23 | 24 | public class AuditRootAudit : IEntityAuditor 25 | { 26 | public void BeforeAudit(ApplicationDbContext context, EntityAudit[] audits) 27 | { 28 | } 29 | 30 | public void OnAudited(ApplicationDbContext context, AuditPredictor predictor) 31 | { 32 | var roots = predictor.Pick().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified); 33 | foreach (var root in roots) 34 | { 35 | if (root.Current.TotalQuantity > root.Current.LimitQuantity) 36 | throw new InvalidOperationException("Invalid TotalQuantity."); 37 | } 38 | } 39 | 40 | public void OnAuditing(ApplicationDbContext context, EntityAudit[] audits) 41 | { 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/AuditValue.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using NStandard.Caching; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.ComponentModel.DataAnnotations.Schema; 6 | 7 | namespace LinqSharp.EFCore.Data.Test; 8 | 9 | [EntityAudit(typeof(AuditValueAuditor))] 10 | public class AuditValue 11 | { 12 | [Key] 13 | public Guid Id { get; set; } 14 | 15 | [ForeignKey(nameof(LevelLink))] 16 | public Guid Level { get; set; } 17 | 18 | [ConcurrencyCheck] 19 | public int Quantity { get; set; } 20 | 21 | public AuditLevel LevelLink { get; set; } 22 | } 23 | 24 | public class AuditValueAuditor : IEntityAuditor 25 | { 26 | public void BeforeAudit(ApplicationDbContext context, EntityAudit[] audits) 27 | { 28 | } 29 | 30 | public void OnAuditing(ApplicationDbContext context, EntityAudit[] audits) 31 | { 32 | var levelCaches = new CacheSet(id => () => context.AuditLevels.Include(x => x.RootLink).First(x => x.Id == id)); 33 | 34 | foreach (var audit in audits) 35 | { 36 | var level = levelCaches[audit.Current.Level].Value; 37 | switch (audit.State) 38 | { 39 | case EntityState.Added: 40 | level.ValueCount += 1; 41 | level.RootLink.TotalQuantity += audit.Current.Quantity; 42 | break; 43 | 44 | case EntityState.Modified: 45 | level.RootLink.TotalQuantity += audit.Current.Quantity - audit.Origin.Quantity; 46 | break; 47 | 48 | case EntityState.Deleted: 49 | level.ValueCount -= 1; 50 | level.RootLink.TotalQuantity -= audit.Current.Quantity; 51 | break; 52 | } 53 | } 54 | } 55 | 56 | public void OnAudited(ApplicationDbContext context, AuditPredictor predictor) 57 | { 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/AutoModel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Annotations; 2 | using LinqSharp.EFCore.Design; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | 6 | namespace LinqSharp.EFCore.Data.Test; 7 | 8 | public class AutoModel : IEntity 9 | { 10 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 11 | public Guid Id { get; set; } 12 | 13 | [AutoCreationTime] 14 | public DateTime CreationTime { get; set; } 15 | 16 | [AutoLastWriteTime] 17 | public DateTime LastWriteTime { get; set; } 18 | 19 | [AutoMonthOnly] 20 | public DateTime Month_DateTime { get; set; } 21 | 22 | [AutoMonthOnly] 23 | public DateTimeOffset Month_DateTimeOffset { get; set; } 24 | 25 | [AutoMonthOnly] 26 | public DateTime? Month_NullableDateTime { get; set; } 27 | 28 | [AutoMonthOnly] 29 | public DateTimeOffset? Month_NullableDateTimeOffset { get; set; } 30 | 31 | [AutoTrim] 32 | public string Trim { get; set; } 33 | 34 | [AutoUpper] 35 | public string Upper { get; set; } 36 | 37 | [AutoLower] 38 | public string Lower { get; set; } 39 | 40 | [AutoCondensed] 41 | public string Condensed { get; set; } 42 | 43 | [AutoEven] 44 | public int Even { get; set; } 45 | 46 | [AutoCreatedBy] 47 | public string CreatedBy { get; set; } 48 | 49 | [AutoUpdatedBy] 50 | public string UpdatedBy { get; set; } 51 | } 52 | 53 | public class AutoEvenAttribute : AutoAttribute 54 | { 55 | public AutoEvenAttribute() : base(AutoState.Added, AutoState.Modified) { } 56 | 57 | public override object Format(object entity, Type propertyType, object value) 58 | { 59 | if (propertyType != typeof(int)) throw Exception_NotSupportedTypes(propertyType, nameof(propertyType)); 60 | 61 | if (value is int @int && @int % 2 == 1) 62 | return @int * 2; 63 | else return 0; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/BulkTestModel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Annotations; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace LinqSharp.EFCore.Data.Test; 6 | 7 | public class BulkTestModel 8 | { 9 | [Key] 10 | public Guid Id { get; set; } 11 | 12 | [StringLength(255)] 13 | [IndexField(IndexType.Unique)] 14 | [Column("UniqueCode")] 15 | public string Code { get; set; } 16 | 17 | [StringLength(255)] 18 | public string Name { get; set; } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/CPKeyModel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Annotations; 2 | 3 | namespace LinqSharp.EFCore.Data.Test; 4 | 5 | public class CPKeyModel 6 | { 7 | [CPKey(1)] 8 | public Guid Id1 { get; set; } 9 | 10 | [CPKey(2)] 11 | public Guid Id2 { get; set; } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/Client.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace LinqSharp.EFCore.Data; 6 | 7 | public class Client 8 | { 9 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 10 | public Guid Id { get; set; } 11 | 12 | [StringLength(255)] 13 | public string Name { get; set; } 14 | 15 | public Address Address { get; set; } 16 | } 17 | 18 | public class CityInfo 19 | { 20 | [StringLength(255)] 21 | public string City { get; set; } 22 | } 23 | 24 | [Owned] 25 | public class Address : CityInfo 26 | { 27 | [StringLength(255)] 28 | public string Street { get; set; } 29 | } 30 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/ConcurrencyModel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Annotations; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace LinqSharp.EFCore.Data.Test; 5 | 6 | [ConcurrencyResolvable] 7 | public class ConcurrencyModel 8 | { 9 | [Key] 10 | public Guid Id { get; set; } 11 | 12 | [ConcurrencyCheck] 13 | public int RowVersion { get; set; } 14 | 15 | public int Value { get; set; } 16 | 17 | [ConcurrencyPolicy(ConcurrencyResolvingMode.DatabaseWins)] 18 | public int DatabaseWinValue { get; set; } 19 | 20 | [ConcurrencyPolicy(ConcurrencyResolvingMode.ClientWins)] 21 | public int ClientWinValue { get; set; } 22 | } 23 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/EntityMonitorModel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Design; 2 | using LinqSharp.EFCore.Entities; 3 | using LinqSharp.EFCore.Providers; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.ComponentModel.DataAnnotations.Schema; 6 | 7 | namespace LinqSharp.EFCore.Data.Test; 8 | 9 | public class EntityMonitorModel : IEntity 10 | { 11 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 12 | public Guid Id { get; set; } 13 | 14 | public DateTime CreationTime { get; set; } 15 | 16 | public string Event { get; set; } 17 | 18 | public string TypeName { get; set; } 19 | 20 | [JsonProvider] 21 | public string[] Key { get; set; } 22 | 23 | [JsonProvider] 24 | public RowChangeInfo ChangeValues { get; set; } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/FacadeModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace LinqSharp.EFCore.Test; 5 | 6 | public class FacadeModel 7 | { 8 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 9 | public Guid Id { get; set; } 10 | 11 | [StringLength(255)] 12 | public string Name { get; set; } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/LS_Index.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Annotations; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace LinqSharp.EFCore.Data.Test; 6 | 7 | public class LS_Index 8 | { 9 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 10 | public Guid Id { get; set; } 11 | 12 | [IndexField(IndexType.Normal)] 13 | public int Int0 { get; set; } 14 | 15 | [IndexField(IndexType.Unique)] 16 | public int Int1 { get; set; } 17 | 18 | [IndexField(IndexType.Unique, Group = "Int2_G1&Int3_G1")] 19 | public int Int2_G1 { get; set; } 20 | 21 | [IndexField(IndexType.Unique, Group = "Int2_G1&Int3_G1")] 22 | public int Int3_G1 { get; set; } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/LS_Name.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Annotations; 2 | using LinqSharp.EFCore.Design; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | 6 | namespace LinqSharp.EFCore.Data; 7 | 8 | public class LS_Name : IEntity 9 | { 10 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 11 | public Guid Id { get; set; } 12 | 13 | [IndexField(IndexType.Unique, Group = "Name&CreationTime")] 14 | [StringLength(255)] 15 | public string Name { get; set; } 16 | 17 | [IndexField(IndexType.Unique, Group = "Name&CreationTime")] 18 | public DateTime CreationTime { get; set; } 19 | 20 | [StringLength(255)] 21 | public string Note { get; set; } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/LS_Provider.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Models.Test; 2 | using LinqSharp.EFCore.Providers; 3 | using NStandard; 4 | using NStandard.Flows; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Text; 7 | 8 | namespace LinqSharp.EFCore.Data.Test; 9 | 10 | public class LS_Provider 11 | { 12 | [Key] 13 | public Guid Id { get; set; } 14 | 15 | [StringLength(127)] 16 | [PasswordProvider] 17 | public string Password { get; set; } 18 | 19 | [StringLength(127)] 20 | [JsonProvider] 21 | public NameModel NameModel { get; set; } 22 | 23 | [StringLength(127)] 24 | [JsonProvider] 25 | public object JsonModel { get; set; } 26 | 27 | [StringLength(127)] 28 | [JsonProvider] 29 | public Dictionary DictionaryModel { get; set; } 30 | 31 | public class PasswordProvider : ProviderAttribute 32 | { 33 | public override string ReadFromProvider(string value) => StringFlow.BytesFromBase64(value).Pipe(Encoding.Unicode.GetString); 34 | public override string WriteToProvider(string model) => model.Pipe(Encoding.Unicode.GetBytes).Pipe(BytesFlow.Base64); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/RowLockModel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Annotations; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace LinqSharp.EFCore.Data; 5 | 6 | public class RowLockModel 7 | { 8 | [Key] 9 | public Guid Id { get; set; } 10 | 11 | public int Value { get; set; } 12 | 13 | [RowLock] 14 | public DateTime? LockDate { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/SimpleModel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Design; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace LinqSharp.EFCore.Data.Test; 6 | 7 | [Flags] 8 | public enum EState 9 | { 10 | Default = 0, 11 | StateA = 1, 12 | StateB = 2, 13 | StateC = 4, 14 | } 15 | 16 | public class SimpleModel : IEntity 17 | { 18 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 19 | public Guid Id { get; set; } 20 | 21 | public string Name { get; set; } 22 | 23 | public int Age { get; set; } 24 | 25 | public DateTime? Birthday { get; set; } 26 | 27 | public EState State { get; set; } 28 | } 29 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/SimpleRow.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace LinqSharp.EFCore.Data.Test; 5 | 6 | [Owned] 7 | public class SimpleRowItemGroup 8 | { 9 | [StringLength(255)] 10 | public string Name { get; set; } 11 | 12 | public int Age { get; set; } 13 | } 14 | 15 | public class SimpleRow 16 | { 17 | [Key] 18 | public Guid Id { get; set; } 19 | 20 | public SimpleRowItemGroup Group { get; set; } = new SimpleRowItemGroup { Name = "(default)" }; 21 | } 22 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/YearMonthModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinqSharp.EFCore.Data; 4 | 5 | public class YearMonthModel 6 | { 7 | [Key] 8 | public Guid Id { get; set; } 9 | 10 | public int Year { get; set; } 11 | 12 | public int Month { get; set; } 13 | 14 | public int Day { get; set; } 15 | 16 | public DateTime Date { get; set; } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/Zipper.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore.Data.Test 2 | { 3 | public interface IZipper 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Data/ZipperModel.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Design; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using System.Diagnostics; 5 | 6 | namespace LinqSharp.EFCore.Data.Test; 7 | 8 | [DebuggerDisplay("{KeyName}: {ZipperStart} ~ {ZipperEnd}")] 9 | public class ZipperModel : IZipperEntity 10 | { 11 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 12 | public Guid Id { get; set; } 13 | 14 | [StringLength(255)] 15 | public string KeyName { get; set; } 16 | 17 | public decimal? Price { get; set; } 18 | public DateTime ZipperStart { get; set; } 19 | public DateTime ZipperEnd { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/DbFuncProviders/DbYearMonthNumber.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Query; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.Linq.Expressions; 4 | 5 | namespace LinqSharp.EFCore.Test.DbFuncProviders; 6 | 7 | public class DbYearMonthNumber : Translator 8 | { 9 | public static int Combine(int year, int month) 10 | { 11 | // This function need to be parsed as `year * 100 + month` 12 | throw CannotBeCalled(); 13 | } 14 | 15 | public override void RegisterAll(ProviderName providerName, ModelBuilder modelBuilder) 16 | { 17 | Register(modelBuilder, () => Combine(default, default), args => 18 | { 19 | return 20 | SqlTranslator.Binary(ExpressionType.Add, 21 | SqlTranslator.Binary(ExpressionType.Multiply, args[0], SqlTranslator.Constant(100)), 22 | args[1]); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/LinqSharp.EFCore.Test.Data.Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | c25f26b1-f307-474f-b9c6-e2d94e6c4c1a 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Data.Shared/Models/NameModel.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore.Models.Test; 2 | 3 | public class NameModel 4 | { 5 | public string Name { get; set; } 6 | public string NickName { get; set; } 7 | public string Tag { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/!DatabaseDepTests/MutilContext.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | 3 | namespace LinqSharp.EFCore.Test; 4 | 5 | public class MutilContext : IDisposable 6 | { 7 | public Lazy SqlServerContext; 8 | public Lazy MySqlContext; 9 | public Lazy SqliteContext; 10 | 11 | public MutilContext() 12 | { 13 | SqlServerContext = new Lazy(() => ApplicationDbContext.UseSqlServer()); 14 | MySqlContext = new Lazy(() => ApplicationDbContext.UseMySql()); 15 | SqliteContext = new Lazy(() => ApplicationDbContext.UseSqlite()); 16 | } 17 | 18 | protected virtual void Disposing() 19 | { 20 | if (SqlServerContext.IsValueCreated) SqlServerContext.Value.Dispose(); 21 | if (MySqlContext.IsValueCreated) MySqlContext.Value.Dispose(); 22 | if (SqliteContext.IsValueCreated) SqliteContext.Value.Dispose(); 23 | } 24 | 25 | private bool disposedValue; 26 | protected virtual void Dispose(bool disposing) 27 | { 28 | if (!disposedValue) 29 | { 30 | if (disposing) 31 | { 32 | Disposing(); 33 | } 34 | disposedValue = true; 35 | } 36 | } 37 | 38 | public void Dispose() 39 | { 40 | Dispose(disposing: true); 41 | GC.SuppressFinalize(this); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/!DatabaseDepTests/MutilContextContainer.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | 3 | namespace LinqSharp.EFCore.Test; 4 | 5 | public class MutilContextContainer : IDisposable 6 | { 7 | public Lazy SqlServerContext; 8 | public Lazy MySqlContext; 9 | public Lazy SqliteContext; 10 | 11 | public MutilContextContainer() 12 | { 13 | SqlServerContext = new Lazy(() => ApplicationDbContext.UseSqlServer()); 14 | MySqlContext = new Lazy(() => ApplicationDbContext.UseMySql()); 15 | SqliteContext = new Lazy(() => ApplicationDbContext.UseSqlite()); 16 | } 17 | 18 | public void Test(TestDatabases testDatabases, Action action) 19 | { 20 | if (testDatabases.HasFlag(TestDatabases.SqlServer)) action(SqlServerContext.Value, TestDatabases.SqlServer); 21 | if (testDatabases.HasFlag(TestDatabases.MySql)) action(MySqlContext.Value, TestDatabases.MySql); 22 | if (testDatabases.HasFlag(TestDatabases.Sqlite)) action(SqliteContext.Value, TestDatabases.Sqlite); 23 | } 24 | 25 | protected virtual void Disposing() 26 | { 27 | if (SqlServerContext.IsValueCreated) SqlServerContext.Value.Dispose(); 28 | if (MySqlContext.IsValueCreated) MySqlContext.Value.Dispose(); 29 | if (SqliteContext.IsValueCreated) SqliteContext.Value.Dispose(); 30 | } 31 | 32 | private bool disposedValue; 33 | protected virtual void Dispose(bool disposing) 34 | { 35 | if (!disposedValue) 36 | { 37 | if (disposing) 38 | { 39 | Disposing(); 40 | } 41 | disposedValue = true; 42 | } 43 | } 44 | 45 | public void Dispose() 46 | { 47 | Dispose(disposing: true); 48 | GC.SuppressFinalize(this); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/!DatabaseDepTests/MySqlTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data; 2 | using LinqSharp.EFCore.Data.Test; 3 | using LinqSharp.EFCore.Translators; 4 | using Microsoft.EntityFrameworkCore; 5 | using Xunit; 6 | 7 | namespace LinqSharp.EFCore.Test; 8 | 9 | public class MySqlTests 10 | { 11 | [Fact] 12 | public void DateTimeTest() 13 | { 14 | static void Test(ApplicationDbContext db, TestDatabases databases) 15 | { 16 | using var trans = db.Database.BeginTransaction(); 17 | using var directScope = db.BeginUnsafeQuery(); 18 | 19 | db.YearMonthModels.Truncate(); 20 | 21 | db.YearMonthModels.AddRange( 22 | [ 23 | new YearMonthModel { Date = new DateTime(2012, 1, 1), Year = 2012, Month = 1, Day = 1 }, 24 | new YearMonthModel { Date = new DateTime(2012, 4, 16), Year = 2012, Month = 4, Day = 16 }, 25 | new YearMonthModel { Date = new DateTime(2012, 5, 18), Year = 2012, Month = 5, Day = 18 }, 26 | ]); 27 | db.SaveChanges(); 28 | 29 | var query = db.YearMonthModels.Where(x => DbDateTime.Create(x.Year, x.Month, x.Day, 1, 1, 1) >= DbDateTime.Create(2012, 4, 16)); 30 | var sql = query.ToQueryString(); 31 | Assert.Equal(2, query.Count()); 32 | 33 | trans.Rollback(); 34 | } 35 | 36 | var container = new MutilContextContainer(); 37 | container.Test(TestDatabases.MySql, Test); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/!DatabaseDepTests/SqlServerTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data; 2 | using LinqSharp.EFCore.Data.Test; 3 | using LinqSharp.EFCore.Translators; 4 | using Microsoft.EntityFrameworkCore; 5 | using Xunit; 6 | 7 | namespace LinqSharp.EFCore.Test; 8 | 9 | public class SqlServerTests 10 | { 11 | [Fact] 12 | public void DateTimeTest() 13 | { 14 | using var db = ApplicationDbContext.UseSqlServer(); 15 | using var trans = db.Database.BeginTransaction(); 16 | 17 | db.YearMonthModels.AddRange( 18 | [ 19 | new YearMonthModel { Date = new DateTime(2012, 1, 1), Year = 2012, Month = 1, Day = 1 }, 20 | new YearMonthModel { Date = new DateTime(2012, 4, 16), Year = 2012, Month = 4, Day = 16 }, 21 | new YearMonthModel { Date = new DateTime(2012, 5, 18), Year = 2012, Month = 5, Day = 18 }, 22 | ]); 23 | db.SaveChanges(); 24 | 25 | var query = db.YearMonthModels.Where(x => DbDateTime.Create(x.Year, x.Month, x.Day, 1, 1, 1) >= DateTime.Now); 26 | var sql = query.ToQueryString(); 27 | Assert.Equal(0, query.Count()); 28 | 29 | trans.Rollback(); 30 | } 31 | 32 | [Fact] 33 | public void RandomTest() 34 | { 35 | using var db = ApplicationDbContext.UseSqlServer(); 36 | using var trans = db.Database.BeginTransaction(); 37 | 38 | db.YearMonthModels.AddRange( 39 | [ 40 | new YearMonthModel { Date = new DateTime(2012, 1, 1), Year = 2012, Month = 1, Day = 1 }, 41 | new YearMonthModel { Date = new DateTime(2012, 4, 16), Year = 2012, Month = 4, Day = 16 }, 42 | new YearMonthModel { Date = new DateTime(2012, 5, 18), Year = 2012, Month = 5, Day = 18 }, 43 | ]); 44 | db.SaveChanges(); 45 | 46 | var query = db.YearMonthModels.Random(2); 47 | var sql = query.ToQueryString(); 48 | Assert.Equal(2, query.Count()); 49 | 50 | trans.Rollback(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/!DatabaseDepTests/TestDatabases.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore.Test; 2 | 3 | [Flags] 4 | public enum TestDatabases 5 | { 6 | SqlServer = 1, 7 | MySql = 2, 8 | Sqlite = 4, 9 | All = SqlServer | MySql | Sqlite, 10 | } 11 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/!Support/EFVersion.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | namespace LinqSharp.EFCore; 9 | 10 | public static class EFVersion 11 | { 12 | public static readonly Version Version = typeof(DbContext).Assembly.GetName().Version; 13 | 14 | public static bool AtLeast(int major, int minor) => Version >= new Version(major, minor); 15 | public static bool AtLeast(int major, int minor, int build) => Version >= new Version(major, minor, build); 16 | public static bool AtLeast(int major, int minor, int build, int revision) => Version >= new Version(major, minor, build, revision); 17 | 18 | public static NotSupportedException NotSupportedException => new($"The version({Version}) of EntityFramework is not supported."); 19 | public static NotSupportedException NeedNewerVersionException => new($"Please use the newer version of LinqSharp.EFCore instead."); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/AgentQueryTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using NStandard; 3 | using Xunit; 4 | 5 | namespace LinqSharp.EFCore.Test; 6 | 7 | public class AgentQueryTests 8 | { 9 | [Fact] 10 | public void AgentTests() 11 | { 12 | var now = DateTime.Now.StartOfSecond(); 13 | 14 | using (var context = ApplicationDbContext.UseMySql()) 15 | using (context.BeginUnsafeQuery()) 16 | { 17 | context.AppRegistries.Truncate(); 18 | } 19 | 20 | using (var context = ApplicationDbContext.UseMySql()) 21 | using (var query = context.BeginAgentQuery(x => x.AppRegistries)) 22 | { 23 | var tom = query.GetAgent("/User/Tom"); 24 | var jerry = query.GetAgent("/User/Jerry"); 25 | 26 | tom.Color = "grey"; 27 | tom.Volume = 50; 28 | tom.LoginTime = now; 29 | 30 | jerry.Theme = "Sky"; 31 | jerry.Color = "brown"; 32 | jerry.Volume = 10; 33 | jerry.LoginTime = now; 34 | jerry.Lock = true; 35 | 36 | context.SaveChanges(); 37 | } 38 | 39 | AppRegistry _tom, _jerry; 40 | 41 | using (var context = ApplicationDbContext.UseMySql()) 42 | using (var query = context.BeginAgentQuery(x => x.AppRegistries)) 43 | { 44 | _tom = query.GetAgent("/User/Tom"); 45 | _jerry = query.GetAgent("/User/Jerry"); 46 | } 47 | 48 | Assert.Equal("Default", _tom.Theme); 49 | Assert.Equal("grey", _tom.Color); 50 | Assert.Equal(50, _tom.Volume); 51 | Assert.Equal(now, _tom.LoginTime); 52 | Assert.False(_tom.Lock); 53 | 54 | Assert.Equal("Sky", _jerry.Theme); 55 | Assert.Equal("brown", _jerry.Color); 56 | Assert.Equal(10, _jerry.Volume); 57 | Assert.Equal(now, _jerry.LoginTime); 58 | Assert.True(_jerry.Lock); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/AuditorTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using Xunit; 3 | 4 | namespace LinqSharp.EFCore.Test; 5 | 6 | public class AuditorTests 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | using (var context = ApplicationDbContext.UseMySql()) 12 | using (var trans = context.Database.BeginTransaction()) 13 | { 14 | var root = new AuditRoot { LimitQuantity = 20 }; 15 | context.AuditRoots.Add(root); 16 | context.SaveChanges(); 17 | 18 | var level1 = new AuditLevel { Root = root.Id }; 19 | var level2 = new AuditLevel { Root = root.Id }; 20 | context.AuditLevels.AddRange(level1, level2); 21 | context.SaveChanges(); 22 | 23 | var value11 = new AuditValue { Level = level1.Id, Quantity = 5 }; 24 | var value12 = new AuditValue { Level = level1.Id, Quantity = 5 }; 25 | var value21 = new AuditValue { Level = level2.Id, Quantity = 4 }; 26 | var value22 = new AuditValue { Level = level2.Id, Quantity = 6 }; 27 | context.AuditValues.AddRange(value11, value12, value21, value22); 28 | context.SaveChanges(); 29 | 30 | Assert.Equal(20, root.TotalQuantity); 31 | 32 | value11.Quantity = 8; 33 | context.AuditValues.Remove(value12); 34 | context.AuditValues.Add(new AuditValue { Level = level1.Id, Quantity = 8 }); 35 | context.AuditLevels.Remove(level2); 36 | context.AuditValues.Remove(value21); 37 | context.SaveChanges(); 38 | 39 | Assert.Equal(16, root.TotalQuantity); 40 | 41 | trans.Rollback(); 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/BulkTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using LinqSharp.EFCore.MySql; 3 | using LinqSharp.EFCore.SqlServer; 4 | using NStandard; 5 | using NStandard.Flows; 6 | using System.Text; 7 | using Xunit; 8 | 9 | namespace LinqSharp.EFCore.Test; 10 | 11 | public class BulkTests 12 | { 13 | static BulkTests() 14 | { 15 | LinqSharpEFRegister.RegisterBulkCopyEngine(ProviderName.MySql, new MySqlBulkCopyEngine()); 16 | LinqSharpEFRegister.RegisterBulkCopyEngine(ProviderName.SqlServer, new SqlServerBulkCopyEngine()); 17 | } 18 | 19 | private static void BulkInsertTest(ApplicationDbContext context) 20 | { 21 | var count = 100; 22 | var guid = Guid.NewGuid(); 23 | 24 | var models = new BulkTestModel[count].Let(i => 25 | { 26 | var guid = Guid.NewGuid(); 27 | return new BulkTestModel 28 | { 29 | Id = guid, 30 | Code = $"{guid} code", 31 | Name = guid.ToString().Pipe(Encoding.Unicode.GetBytes).Pipe(BytesFlow.Base58), 32 | }; 33 | }); 34 | 35 | using (context.BeginUnsafeQuery()) 36 | { 37 | context.BulkTestModels.Truncate(); 38 | context.BulkTestModels.BulkInsert(models); 39 | Assert.Equal(count, context.BulkTestModels.Count()); 40 | } 41 | } 42 | 43 | [Fact] 44 | public void BulkInsert_SqlServerTest() 45 | { 46 | using var context = ApplicationDbContext.UseSqlServer(); 47 | BulkInsertTest(context); 48 | } 49 | 50 | [Fact] 51 | public void BulkInsert_MySqlTest() 52 | { 53 | using var context = ApplicationDbContext.UseMySql(); 54 | BulkInsertTest(context); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/Comparers/SequenceComparerTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.Comparers; 2 | using Xunit; 3 | 4 | namespace LinqSharp.EFCore.Test.Shared.Comparers; 5 | 6 | public class SequenceComparerTests 7 | { 8 | [Fact] 9 | public void NormalTest() 10 | { 11 | var x = new List { 1, 2, 3 }; 12 | var y = new List { 1, 2, 3 }; 13 | var z = new List { 1, 2, 4 }; 14 | var comparer = new SequenceComparer(); 15 | Assert.True(comparer.Equals(x, y)); 16 | Assert.False(comparer.Equals(x, z)); 17 | Assert.False(comparer.Equals(x, null)); 18 | Assert.False(comparer.Equals(null, y)); 19 | Assert.True(comparer.Equals(null, null)); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/DbContextExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data; 2 | using LinqSharp.EFCore.Data.Test; 3 | using Xunit; 4 | 5 | namespace LinqSharp.EFCore.Test; 6 | 7 | public class DbContextExtensionsTests 8 | { 9 | [Fact] 10 | public void Test1() 11 | { 12 | using var mysql = ApplicationDbContext.UseMySql(); 13 | var name = mysql.GetTableName(); 14 | Assert.Equal("LS_Names", name); 15 | } 16 | } -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/DbFunctionTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using LinqSharp.EFCore.Translators; 3 | using Microsoft.EntityFrameworkCore; 4 | using Xunit; 5 | 6 | namespace LinqSharp.EFCore.Test; 7 | 8 | public class DbFunctionTests 9 | { 10 | [Fact] 11 | public void RandomTest() 12 | { 13 | using var mysql = ApplicationDbContext.UseMySql(); 14 | var query = mysql.SimpleModels.Random(2); 15 | var sql = query.ToQueryString(); 16 | string expectedSql; 17 | 18 | #if EFCORE5_0_OR_GREATER 19 | expectedSql = @" 20 | SELECT `s`.`Id`, `s`.`Age`, `s`.`Birthday`, `s`.`Name`, `s`.`State` 21 | FROM `SimpleModels` AS `s` 22 | ORDER BY RAND() 23 | LIMIT 2"; 24 | 25 | #elif EFCORE3_1_OR_GREATER 26 | expectedSql = @"SELECT `s`.`Id`, `s`.`Age`, `s`.`Birthday`, `s`.`Name`, `s`.`State` 27 | FROM `SimpleModels` AS `s` 28 | ORDER BY RAND() 29 | LIMIT @__p_0; 30 | "; 31 | 32 | #elif EFCORE2_1_OR_GREATER 33 | expectedSql = @"SELECT `x`.`Id`, `x`.`Age`, `x`.`Birthday`, `x`.`Name`, `x`.`State` 34 | FROM `SimpleModels` AS `x` 35 | ORDER BY RAND() 36 | LIMIT 2; 37 | "; 38 | #endif 39 | Assert.Equal(expectedSql, sql); 40 | } 41 | 42 | [Fact] 43 | public void RowNumberTest() 44 | { 45 | using var mysql = ApplicationDbContext.UseMySql(); 46 | var query = 47 | ( 48 | from x in mysql.Orders 49 | let rn = DbRowNumber.RowNumber( 50 | x.EmployeeID, // partition by 51 | x.OrderID, // order by 52 | true // desc 53 | ) 54 | select new 55 | { 56 | rn, 57 | x.OrderID, 58 | x.EmployeeID, 59 | } 60 | ); 61 | var sql = query.ToQueryString(); 62 | 63 | var results = query.ToArray(); 64 | 65 | string expectedSql; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/DbYearMonthNumberTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using LinqSharp.EFCore.Test.DbFuncProviders; 3 | using Microsoft.EntityFrameworkCore; 4 | using Xunit; 5 | 6 | namespace LinqSharp.EFCore.Test; 7 | 8 | public class DbYearMonthNumberTests 9 | { 10 | [Fact] 11 | public void Test() 12 | { 13 | using var context = ApplicationDbContext.UseMySql(); 14 | var sql = context.YearMonthModels.Where(x => DbYearMonthNumber.Combine(x.Year, x.Month) > 201204).ToQueryString(); 15 | 16 | #if EFCORE5_0_OR_GREATER 17 | Assert.Equal(@"SELECT `y`.`Id`, `y`.`Date`, `y`.`Day`, `y`.`Month`, `y`.`Year` 18 | FROM `YearMonthModels` AS `y` 19 | WHERE ((`y`.`Year` * 100) + `y`.`Month`) > 201204", sql); 20 | 21 | #elif EFCORE3_1_OR_GREATER 22 | Assert.Equal(@"SELECT `y`.`Id`, `y`.`Date`, `y`.`Day`, `y`.`Month`, `y`.`Year` 23 | FROM `YearMonthModels` AS `y` 24 | WHERE ((`y`.`Year` * 100) + `y`.`Month`) > 201204; 25 | ", sql); 26 | 27 | #else 28 | Assert.Equal(@"SELECT `x`.`Id`, `x`.`Date`, `x`.`Day`, `x`.`Month`, `x`.`Year` 29 | FROM `YearMonthModels` AS `x` 30 | WHERE ((`x`.`Year` * 100) + `x`.`Month`) > 201204; 31 | ", sql); 32 | #endif 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/ExpressionExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using Northwnd.Data; 2 | using System.Linq.Expressions; 3 | using Xunit; 4 | 5 | namespace LinqSharp.EFCore.Test; 6 | 7 | public class ExpressionExtensionsTests 8 | { 9 | [Fact] 10 | public void Test() 11 | { 12 | var exp = new Expression>[] 13 | { 14 | x => x.OrderID == 1, 15 | x => x.ProductID == 1, 16 | x => x.UnitPrice == 1, 17 | }.LambdaJoin(Expression.OrElse); 18 | Assert.Equal("x => (((x.OrderID == 1) OrElse (x.ProductID == 1)) OrElse (x.UnitPrice == 1))", exp.ToString()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/IEntityTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Design; 2 | using NStandard; 3 | using Xunit; 4 | 5 | namespace LinqSharp.EFCore.Test; 6 | 7 | public class IEntityTests 8 | { 9 | public class Entity : IEntity 10 | { 11 | public string String { get; set; } 12 | public int Int { get; set; } 13 | } 14 | 15 | [Fact] 16 | public void Test1() 17 | { 18 | var a = new Entity() { String = "123", Int = 1 }; 19 | var b = new Entity().Pipe(x => x.Accept(a)); 20 | var c = new Entity().Pipe(x => x.Accept(a, m => new { m.String })); 21 | 22 | Assert.Equal("123", b.String); 23 | Assert.Equal(1, b.Int); 24 | 25 | Assert.Equal("123", c.String); 26 | Assert.Equal(0, c.Int); 27 | } 28 | 29 | public class MyEntity : IEntity 30 | { 31 | public string Class { get; set; } 32 | public string Name { get; set; } 33 | public string Comment { get; set; } 34 | public DateTime? RegisterDate { get; set; } 35 | } 36 | 37 | [Fact] 38 | public void Test2() 39 | { 40 | var entity1 = new MyEntity 41 | { 42 | Class = "123", 43 | Name = "aaa", 44 | Comment = "comment", 45 | }; 46 | var entity2 = new MyEntity 47 | { 48 | RegisterDate = DateTime.Now, 49 | }; 50 | entity2.Accept(entity1, m => new { m.Class }); 51 | entity2.Accept(entity1, m => m.Comment); 52 | entity2.Accept(entity1, m => m.RegisterDate); 53 | 54 | Assert.Equal(entity2.Class, entity1.Class); 55 | Assert.Equal(entity2.Comment, entity1.Comment); 56 | Assert.NotEqual(entity2.Name, entity1.Name); 57 | Assert.Null(entity2.RegisterDate); 58 | } 59 | 60 | [Fact] 61 | public void Test3() 62 | { 63 | var entity1 = new MyEntity 64 | { 65 | Class = "123", 66 | Name = "aaa", 67 | }; 68 | 69 | var dict = entity1.ToDisplayDictionary(nameof(MyEntity.Name)); 70 | Assert.Equal("aaa", dict[nameof(MyEntity.Name)]); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/IndexByTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Models.Test; 2 | using NStandard; 3 | using Xunit; 4 | 5 | namespace LinqSharp.EFCore.Test.Shared; 6 | 7 | public class IndexTests 8 | { 9 | private readonly NameModel[] _models = new NameModel[10].Let(i => new NameModel 10 | { 11 | Name = i.ToString(), 12 | NickName = $"NN: {i}", 13 | Tag = (i / 5).ToString() 14 | }); 15 | 16 | [Fact] 17 | public void IndexingNormalTest() 18 | { 19 | var modelsByTag = _models.IndexBy(x => x.Tag); 20 | var modelsByNameNickName = _models.IndexBy(x => new { x.Name, x.NickName }); 21 | 22 | Assert.Equal(0, modelsByTag["0"].Sum(x => int.Parse(x.Tag))); 23 | Assert.Equal(5, modelsByTag["1"].Sum(x => int.Parse(x.Tag))); 24 | Assert.Equal(0, modelsByTag["2"].Sum(x => int.Parse(x.Tag))); 25 | Assert.Equal("1", modelsByNameNickName[new { Name = "5", NickName = "NN: 5" }].First().Tag); 26 | } 27 | 28 | [Fact] 29 | public void IndexingNullTest() 30 | { 31 | var modelByTag = _models.IndexBy(x => (string)null); 32 | Assert.Equal(5, modelByTag[null].Sum(x => int.Parse(x.Tag))); 33 | } 34 | 35 | [Fact] 36 | public void UniqueIndexingNormalTest() 37 | { 38 | var modelByTag = ( 39 | from x in _models 40 | group x by x.Tag into g 41 | select g.First() 42 | ).UniqueIndexBy(x => x.Tag); 43 | 44 | Assert.Equal("0", modelByTag["0"].Target.Tag); 45 | Assert.Equal("1", modelByTag["1"].Target.Tag); 46 | Assert.Null(modelByTag["2"]); 47 | } 48 | 49 | [Fact] 50 | public void UniqueIndexingNullTest() 51 | { 52 | var modelByTag = _models.Take(1).UniqueIndexBy(x => (string)null); 53 | Assert.Equal("0", modelByTag[null].Target.Tag); 54 | } 55 | 56 | [Fact] 57 | public void UniqueIndexingThrowTest() 58 | { 59 | var indexed = _models.UniqueIndexBy(x => x.Tag); 60 | Assert.ThrowsAny(() => indexed[null]); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/IndexingTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.Query; 2 | using Xunit; 3 | 4 | namespace LinqSharp.EFCore.Test; 5 | 6 | public class IndexingTests 7 | { 8 | [Fact] 9 | public void NormalTest() 10 | { 11 | var indexing = new Indexing([1, 2, 2, 3], x => x); 12 | Assert.Equal(0, indexing[0].Count); 13 | Assert.Equal(1, indexing[1].Count); 14 | Assert.Equal(2, indexing[2].Count); 15 | } 16 | 17 | [Fact] 18 | public void EmptyTest() 19 | { 20 | var indexing = new Indexing([1, 2, 3], x => x); 21 | indexing.Remove(2); 22 | Assert.Empty(indexing[2]); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/LinqSharp.EFCore.Test.Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0b9e78ed-ec9e-4ed2-be97-5cf09b0b429d 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/PagedEnumerableTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace LinqSharp.EFCore.Test; 4 | 5 | public class PagedEnumerableTests 6 | { 7 | [Fact] 8 | public void Test1() 9 | { 10 | var items = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 11 | 12 | { 13 | var page = items.Page(1, 3); 14 | Assert.True(page.IsFristPage); 15 | Assert.False(page.IsLastPage); 16 | Assert.Equal(4, page.PageCount); 17 | Assert.Equal(10, page.SourceCount); 18 | } 19 | { 20 | var page = items.Page(1, 5); 21 | Assert.True(page.IsFristPage); 22 | Assert.False(page.IsLastPage); 23 | Assert.Equal(2, page.PageCount); 24 | Assert.Equal(10, page.SourceCount); 25 | } 26 | { 27 | var page = items.Page(1, 10); 28 | Assert.True(page.IsFristPage); 29 | Assert.True(page.IsLastPage); 30 | Assert.Equal(1, page.PageCount); 31 | Assert.Equal(10, page.SourceCount); 32 | } 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/PartitionTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace LinqSharp.EFCore.Test; 4 | 5 | public class PartitionTests 6 | { 7 | [Fact] 8 | public void Test1() 9 | { 10 | var arr = new[] { 1, 2, 3 }; 11 | var partitions = arr.PartitionBy(x => x < 3, x => x < 5, x => x < 7); 12 | Assert.Equal(new[] { 1, 2 }, partitions[0]); 13 | Assert.Equal(new[] { 3 }, partitions[1]); 14 | Assert.Equal(Array.Empty(), partitions[2]); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/ProviderNameTests.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Data.Test; 2 | using Xunit; 3 | 4 | namespace LinqSharp.EFCore.Test; 5 | 6 | public class ProviderNameTests 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | using var context = ApplicationDbContext.UseMySql(); 12 | var providerName = context.SimpleRows.GetProviderName(); 13 | Assert.Equal(ProviderName.MySql, providerName); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/QSum_And_QAverageTests.cs: -------------------------------------------------------------------------------- 1 | using NStandard.Measures; 2 | using Xunit; 3 | 4 | namespace LinqSharp.EFCore.Test; 5 | 6 | public class QSum_And_QAverageTests 7 | { 8 | [Obsolete] 9 | public struct b(decimal value) : IMeasurable 10 | { 11 | public decimal Value { get; set; } = value; 12 | public static implicit operator b(int n) => new(n); 13 | } 14 | 15 | [Fact] 16 | public void ValueTest() 17 | { 18 | b[] values = [10, 20, 45]; 19 | Assert.Equal(75, values.QSum()); 20 | Assert.Equal(25, values.QAverage()); 21 | Assert.Equal(25, values.QAverageOrDefault()); 22 | Assert.Equal(25, values.QAverageOrDefault(-1)); 23 | } 24 | 25 | [Fact] 26 | public void NullableValueTest() 27 | { 28 | b?[] values = [10, 20, 45]; 29 | Assert.Equal(75, values.QSum()); 30 | Assert.Equal(25, values.QAverage()); 31 | Assert.Equal(25, values.QAverageOrDefault()); 32 | Assert.Equal(25, values.QAverageOrDefault(-1)); 33 | } 34 | 35 | [Fact] 36 | public void EmptyValueTest() 37 | { 38 | b[] values = []; 39 | Assert.Equal(0, values.QSum()); 40 | Assert.ThrowsAny(() => values.QAverage()); 41 | Assert.Equal(default, values.QAverageOrDefault()); 42 | Assert.Equal(-1, values.QAverageOrDefault(-1)); 43 | } 44 | 45 | [Fact] 46 | public void EmptyNullableValueTest() 47 | { 48 | b?[] values = []; 49 | Assert.Equal(0, values.QSum()); 50 | Assert.Null(values.QAverage()); 51 | Assert.Null(values.QAverageOrDefault()); 52 | Assert.Equal(-1, values.QAverageOrDefault(-1)); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/SameOrDefaultTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace LinqSharp.EFCore.Test; 4 | 5 | public class SameOrDefaultTests 6 | { 7 | [Fact] 8 | public void SameOrDefaultTest() 9 | { 10 | Assert.Null(new int?[] { null, 1, 1 }.SameOrDefault()); 11 | Assert.Null(new int?[] { 0, 1, 1 }.SameOrDefault()); 12 | Assert.Equal(1, new int?[] { 1, 1, 1 }.SameOrDefault()); 13 | } 14 | 15 | [Fact] 16 | public void SameTest() 17 | { 18 | Assert.ThrowsAny(() => new int?[] { null, 1, 1 }.Same()); 19 | Assert.ThrowsAny(() => new int?[] { 0, 1, 1 }.Same()); 20 | Assert.Equal(1, new int?[] { 1, 1, 1 }.Same()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/extern/TestId.cs: -------------------------------------------------------------------------------- 1 | namespace NStandard.Diagnostics; 2 | 3 | public struct TestId 4 | { 5 | public int ThreadId { get; set; } 6 | public int InvokeNumber { get; set; } 7 | 8 | public TestId(int threadId, int invokeNumber) 9 | { 10 | ThreadId = threadId; 11 | InvokeNumber = invokeNumber; 12 | } 13 | 14 | public override string ToString() 15 | { 16 | return $"Thread:{ThreadId}({InvokeNumber})"; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/extern/TestReport.cs: -------------------------------------------------------------------------------- 1 | namespace NStandard.Diagnostics; 2 | 3 | public class TestReport 4 | { 5 | public TestReport(TestResult[] results) 6 | { 7 | Results = results; 8 | } 9 | 10 | public TimeSpan? AverageElapsed { get; private set; } 11 | public TimeSpan? TotalElapsed { get; private set; } 12 | public TimeSpan? MinElapsed { get; private set; } 13 | public TimeSpan? MaxElapsed { get; private set; } 14 | 15 | private TestResult[] _results; 16 | public TestResult[] Results 17 | { 18 | get => _results; 19 | set 20 | { 21 | _results = value; 22 | var allTicks = value.Where(x => x.Success).Select(x => x.Elapsed.Ticks); 23 | if (allTicks.Any()) 24 | { 25 | AverageElapsed = new TimeSpan((long)allTicks.Average()); 26 | TotalElapsed = new TimeSpan(allTicks.Sum()); 27 | MinElapsed = new TimeSpan(allTicks.Min()); 28 | MaxElapsed = new TimeSpan(allTicks.Max()); 29 | } 30 | else 31 | { 32 | AverageElapsed = default; 33 | TotalElapsed = default; 34 | MinElapsed = default; 35 | MaxElapsed = default; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LinqSharp.EFCore.Test/LinqSharp.EFCore.Test.Shared/extern/TestResult.cs: -------------------------------------------------------------------------------- 1 | namespace NStandard.Diagnostics; 2 | 3 | public struct TestResult 4 | { 5 | public int ThreadId { get; set; } 6 | public int InvokeNumber { get; set; } 7 | public bool Success { get; set; } 8 | 9 | public TRet Return { get; set; } 10 | public TimeSpan Elapsed { get; set; } 11 | public Exception Exception { get; set; } 12 | 13 | public override string ToString() 14 | { 15 | return $"{{ Id: {ThreadId}:{InvokeNumber}, Success = {Success}, Elapsed = {Elapsed} }}"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Abstractions/BulkCopyEngine.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Collections.Generic; 7 | using System.Data; 8 | using System.Data.Common; 9 | 10 | namespace LinqSharp.EFCore 11 | { 12 | public abstract class BulkCopyEngine 13 | { 14 | public abstract string[] GetOrderedColumns(DbConnection connection, string tableName); 15 | public abstract void WriteToServer(DbConnection connection, string tableName, IEnumerable sources); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Abstractions/LinqSharp.EFCore.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;net5.0;net6.0;net7.0 6 | 7 | 8 | preview 9 | 0.1.0 10 | zmjack 11 | linqsharp.net 12 | LinqSharp is a smarter linq extension. It allows you to write simpler code to generate complex queries. 13 | LICENSE 14 | https://github.com/zmjack/LinqSharp 15 | ©2020 linqsharp.net 16 | true 17 | https://github.com/zmjack/LinqSharp 18 | git 19 | LinqSharp.EFCore.Abstractions 20 | Linq EntityFramework 21 | LinqSharp.png 22 | LinqSharp.EFCore 23 | 24 | 25 | 26 | 27 | 28 | 29 | none 30 | false 31 | 32 | 33 | 34 | 35 | True 36 | 37 | 38 | 39 | True 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using NStandard; 7 | 8 | namespace LinqSharp.EFCore.Annotations; 9 | 10 | public abstract class AutoAttribute : Attribute 11 | { 12 | private readonly AutoState[] SupportedStates = [AutoState.Added, AutoState.Modified, AutoState.Deleted]; 13 | private readonly AutoState[] _states; 14 | 15 | private ArgumentException Exception_NotSupportedStates(string paramName) 16 | { 17 | throw new ArgumentException($"Only {SupportedStates.Join(", ")} are supported.", paramName); 18 | } 19 | 20 | protected ArgumentException Exception_NotSupportedTypes(Type propertyType, string paramName) 21 | { 22 | throw new ArgumentException($"The {propertyType} is not supported for {GetType()}.", paramName); 23 | } 24 | 25 | public AutoAttribute() 26 | { 27 | _states = SupportedStates; 28 | } 29 | 30 | public AutoAttribute(params AutoState[] states) 31 | { 32 | if (!states.All(x => SupportedStates.Contains(x))) throw Exception_NotSupportedStates(nameof(states)); 33 | 34 | _states = states; 35 | } 36 | 37 | public AutoState[] States => _states; 38 | 39 | public abstract object? Format(object entity, Type propertyType, object? value); 40 | } 41 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoCondensedAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using NStandard; 7 | 8 | namespace LinqSharp.EFCore.Annotations; 9 | 10 | [AttributeUsage(AttributeTargets.Property)] 11 | public sealed class AutoCondensedAttribute : AutoAttribute 12 | { 13 | public bool ReserveNewLine { get; set; } 14 | public bool Nullable { get; set; } 15 | 16 | public AutoCondensedAttribute() : base(AutoState.Added, AutoState.Modified) { } 17 | 18 | public override object? Format(object entity, Type propertyType, object? value) 19 | { 20 | if (propertyType != typeof(string)) throw Exception_NotSupportedTypes(propertyType, nameof(propertyType)); 21 | 22 | if (value is null) return Nullable ? null : string.Empty; 23 | 24 | var @string = value as string; 25 | if (ReserveNewLine) 26 | { 27 | //TODO: Optimizable 28 | var normalized = @string.NormalizeNewLine(); 29 | var parts = from part in normalized.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) select part.Unique(); 30 | return parts.Join(Environment.NewLine); 31 | } 32 | else return @string.Unique(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoCreatedByAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Annotations.Params; 7 | 8 | namespace LinqSharp.EFCore.Annotations; 9 | 10 | [AttributeUsage(AttributeTargets.Property)] 11 | public sealed class AutoCreatedByAttribute : SpecialAutoAttribute 12 | { 13 | public AutoCreatedByAttribute() : base(AutoState.Added) { } 14 | 15 | public override object? Format(object entity, Type propertyType, UserParam value) 16 | { 17 | return value.CurrentUser; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoCreationTimeAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Annotations.Params; 7 | using NStandard; 8 | 9 | namespace LinqSharp.EFCore.Annotations; 10 | 11 | [AttributeUsage(AttributeTargets.Property)] 12 | public sealed class AutoCreationTimeAttribute : SpecialAutoAttribute 13 | { 14 | private static readonly Type[] DateTimeTypes = [typeof(DateTime), typeof(DateTime?)]; 15 | private static readonly Type[] DateTimeOffsetTypes = [typeof(DateTimeOffset), typeof(DateTimeOffset?)]; 16 | 17 | public AutoCreationTimeAttribute() : base(AutoState.Added) { } 18 | 19 | public override object? Format(object entity, Type propertyType, TimestampParam value) 20 | { 21 | if (DateTimeTypes.Contains(propertyType)) return value.Now; 22 | else if (DateTimeOffsetTypes.Contains(propertyType)) return value.NowOffset; 23 | else throw new ArgumentException($"Only {DateTimeTypes.Join(", ")}, {DateTimeOffsetTypes.Join(", ")} are supported.", nameof(propertyType)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoLastWriteTimeAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Annotations.Params; 7 | using NStandard; 8 | 9 | namespace LinqSharp.EFCore.Annotations; 10 | 11 | [AttributeUsage(AttributeTargets.Property)] 12 | public sealed class AutoLastWriteTimeAttribute : SpecialAutoAttribute 13 | { 14 | private static readonly Type[] DateTimeTypes = [typeof(DateTime), typeof(DateTime?)]; 15 | private static readonly Type[] DateTimeOffsetTypes = [typeof(DateTimeOffset), typeof(DateTimeOffset?)]; 16 | 17 | public AutoLastWriteTimeAttribute() : base(AutoState.Added, AutoState.Modified) { } 18 | 19 | public override object? Format(object entity, Type propertyType, TimestampParam value) 20 | { 21 | if (DateTimeTypes.Contains(propertyType)) return value.Now; 22 | else if (DateTimeOffsetTypes.Contains(propertyType)) return value.NowOffset; 23 | else throw new ArgumentException($"Only {DateTimeTypes.Join(", ")}, {DateTimeOffsetTypes.Join(", ")} are supported.", nameof(propertyType)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoLowerAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations; 7 | 8 | [AttributeUsage(AttributeTargets.Property)] 9 | public sealed class AutoLowerAttribute : AutoAttribute 10 | { 11 | public AutoLowerAttribute() : base(AutoState.Added, AutoState.Modified) { } 12 | public override object? Format(object entity, Type propertyType, object? value) 13 | { 14 | if (propertyType != typeof(string)) throw Exception_NotSupportedTypes(propertyType, nameof(propertyType)); 15 | 16 | return (value as string)?.ToLower(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoMonthOnlyAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using NStandard; 7 | 8 | namespace LinqSharp.EFCore.Annotations; 9 | 10 | [AttributeUsage(AttributeTargets.Property)] 11 | public sealed class AutoMonthOnlyAttribute : AutoAttribute 12 | { 13 | public AutoMonthOnlyAttribute() : base(AutoState.Added, AutoState.Modified) { } 14 | public override object? Format(object entity, Type propertyType, object? value) 15 | { 16 | if (propertyType == typeof(DateTime)) return ((DateTime)value!).StartOfMonth(); 17 | if (propertyType == typeof(DateTime?)) return ((DateTime?)value)?.StartOfMonth(); 18 | 19 | if (propertyType == typeof(DateTimeOffset)) return ((DateTimeOffset)value!).StartOfMonth(); 20 | if (propertyType == typeof(DateTimeOffset?)) return ((DateTimeOffset?)value)?.StartOfMonth(); 21 | 22 | #if NET6_0_OR_GREATER 23 | if (propertyType == typeof(DateOnly)) return ((DateOnly)value!).StartOfMonth(); 24 | if (propertyType == typeof(DateOnly?)) return ((DateOnly?)value)?.StartOfMonth(); 25 | 26 | throw new ArgumentException($"Only DateTime, DateTimeOffset, DateOnly are supported.", nameof(propertyType)); 27 | #else 28 | throw new ArgumentException($"Only DateTime, DateTimeOffset are supported.", nameof(propertyType)); 29 | #endif 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoTrimAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations; 7 | 8 | [AttributeUsage(AttributeTargets.Property)] 9 | public sealed class AutoTrimAttribute : AutoAttribute 10 | { 11 | public AutoTrimAttribute() : base(AutoState.Added, AutoState.Modified) { } 12 | public override object? Format(object entity, Type propertyType, object? value) 13 | { 14 | if (propertyType != typeof(string)) throw Exception_NotSupportedTypes(propertyType, nameof(propertyType)); 15 | 16 | return (value as string)?.Trim(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoUpdatedByAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Annotations.Params; 7 | 8 | namespace LinqSharp.EFCore.Annotations; 9 | 10 | [AttributeUsage(AttributeTargets.Property)] 11 | public sealed class AutoUpdatedByAttribute : SpecialAutoAttribute 12 | { 13 | public AutoUpdatedByAttribute() : base(AutoState.Added, AutoState.Modified) { } 14 | 15 | public override object? Format(object entity, Type propertyType, UserParam value) 16 | { 17 | return value.CurrentUser; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/AutoUpperAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations; 7 | 8 | [AttributeUsage(AttributeTargets.Property)] 9 | public sealed class AutoUpperAttribute : AutoAttribute 10 | { 11 | public AutoUpperAttribute() : base(AutoState.Added, AutoState.Modified) { } 12 | public override object? Format(object entity, Type propertyType, object? value) 13 | { 14 | if (propertyType != typeof(string)) throw Exception_NotSupportedTypes(propertyType, nameof(propertyType)); 15 | 16 | return (value as string)?.ToUpper(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/CPKeyAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations; 7 | 8 | [AttributeUsage(AttributeTargets.Property)] 9 | public sealed class CPKeyAttribute(int order) : Attribute 10 | { 11 | public int Order { get; set; } = order; 12 | } 13 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/ConcurrencyPolicyAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations; 7 | 8 | 9 | [AttributeUsage(AttributeTargets.Property)] 10 | public sealed class ConcurrencyPolicyAttribute(ConcurrencyResolvingMode mode) : Attribute 11 | { 12 | public ConcurrencyResolvingMode Mode { get; set; } = mode; 13 | } 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/ConcurrencyResolvableAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore.Annotations; 2 | 3 | [AttributeUsage(AttributeTargets.Class)] 4 | public sealed class ConcurrencyResolvableAttribute : Attribute 5 | { 6 | } 7 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/ConcurrencyResolvingMode.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | #if !NETSTANDARD2_1 7 | using System.ComponentModel.DataAnnotations; 8 | #endif 9 | 10 | namespace LinqSharp.EFCore.Annotations; 11 | 12 | public enum ConcurrencyResolvingMode 13 | { 14 | /// 15 | /// Client Win. (Default) 16 | /// 17 | ClientWins = 0, 18 | 19 | /// 20 | /// Database Win. 21 | /// 22 | DatabaseWins = 1, 23 | 24 | #if !NETSTANDARD2_1 25 | /// 26 | /// [Warning] Do not specify manually. 27 | /// If property is one of or 29 | #else 30 | /// 31 | /// [Warning] Do not specify manually. 32 | /// If property is one of ConcurrencyCheckAttribute or TimestampAttribute, it will be set automatically. 33 | /// 34 | #endif 35 | Check = 0x100, 36 | } 37 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/IndexFieldAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations; 7 | 8 | public enum IndexType { Normal, Unique } 9 | 10 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 11 | public sealed class IndexFieldAttribute(IndexType type) : Attribute 12 | { 13 | public string? Group { get; set; } 14 | public IndexType Type { get; set; } = type; 15 | } 16 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/NotAcceptableAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations; 7 | 8 | [AttributeUsage(AttributeTargets.Property)] 9 | public sealed class NotAcceptableAttribute : Attribute { } 10 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/Params/IAutoParam.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations.Params; 7 | 8 | public interface IAutoParam 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/Params/TimestampParam.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations.Params; 7 | 8 | public sealed class TimestampParam : IAutoParam 9 | { 10 | public DateTime Now { get; set; } 11 | public DateTimeOffset NowOffset { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/Params/UserParam.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations.Params; 7 | 8 | public sealed class UserParam : IAutoParam 9 | { 10 | public string? CurrentUser { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/RelatedAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore.Annotations; 2 | 3 | [AttributeUsage(AttributeTargets.Property)] 4 | public class RelatedAttribute : Attribute 5 | { 6 | } 7 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/RowLockAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Annotations; 7 | 8 | [AttributeUsage(AttributeTargets.Property)] 9 | public sealed class RowLockAttribute : Attribute 10 | { 11 | public string[]? Columns { get; } 12 | public int Order { get; set; } 13 | 14 | public RowLockAttribute(string[]? columns = null, int order = 0) 15 | { 16 | Columns = columns; 17 | Order = order; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Annotations/SpecialAutoAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Annotations.Params; 7 | 8 | namespace LinqSharp.EFCore.Annotations; 9 | 10 | public interface ISpecialAutoAttribute 11 | { 12 | } 13 | 14 | public abstract class SpecialAutoAttribute : AutoAttribute, ISpecialAutoAttribute where TAutoTag : IAutoParam 15 | { 16 | public SpecialAutoAttribute() : base() { } 17 | public SpecialAutoAttribute(params AutoState[] states) : base(states) { } 18 | 19 | public override object? Format(object entity, Type propertyType, object? value) 20 | { 21 | if (value is not TAutoTag autoTag) throw new ArgumentException($"Only {typeof(TAutoTag)} is supported.", nameof(value)); 22 | 23 | return Format(entity, propertyType, autoTag); 24 | } 25 | public abstract object? Format(object entity, Type propertyType, TAutoTag value); 26 | } 27 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/AutoMode.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore; 2 | 3 | public enum AutoMode 4 | { 5 | Auto = 0, 6 | Free = 1, 7 | Suppress = 2, 8 | } 9 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/AutoState.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore; 7 | 8 | /// 9 | /// Similar to EntityState. 10 | /// 11 | public enum AutoState 12 | { 13 | // 14 | // Summary: 15 | // The entity is being tracked by the context and exists in the database. It has 16 | // been marked for deletion from the database. 17 | Deleted = 2, 18 | // 19 | // Summary: 20 | // The entity is being tracked by the context and exists in the database. Some or 21 | // all of its property values have been modified. 22 | Modified = 3, 23 | // 24 | // Summary: 25 | // The entity is being tracked by the context but does not yet exist in the database. 26 | Added = 4, 27 | } 28 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Design/EntityAuditAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Design; 7 | 8 | [AttributeUsage(AttributeTargets.Class)] 9 | public class EntityAuditAttribute : Attribute 10 | { 11 | public Type EntityAuditorType { get; set; } 12 | 13 | public EntityAuditAttribute(Type entityAuditorType) 14 | { 15 | EntityAuditorType = entityAuditorType; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Design/IConcurrencyResolvable.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Design; 7 | 8 | public interface IConcurrencyResolvableContext 9 | { 10 | public int MaxConcurrencyRetry { get; } 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Design/IUserTraceable.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Design; 7 | 8 | public interface IUserTraceable 9 | { 10 | string CurrentUser { get; } 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Design/ViewAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore.Design; 2 | 3 | [AttributeUsage(AttributeTargets.Class)] 4 | public class ViewAttribute(string name) : Attribute 5 | { 6 | public string Name { get; set; } = name; 7 | } 8 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/EntityAnnotation.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore; 7 | 8 | [Flags] 9 | public enum EntityAnnotation 10 | { 11 | Index = 1, 12 | Provider = 2, 13 | CompositeKey = 4, 14 | All = Index | Provider | CompositeKey, 15 | } 16 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/LinqSharp.EFCore.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | net5.0;net6.0;net7.0;net8.0; 6 | netstandard2.0;netstandard2.1 7 | 8 | preview 9 | 0.8.20 10 | zmjack 11 | linqsharp.net 12 | LinqSharp is a smarter linq extension. It allows you to write simpler code to generate complex queries. 13 | LICENSE 14 | https://github.com/zmjack/LinqSharp 15 | ©2020 linqsharp.net 16 | true 17 | https://github.com/zmjack/LinqSharp 18 | git 19 | LinqSharp.EFCore.Core 20 | Linq EntityFramework 21 | LinqSharp.png 22 | LinqSharp.EFCore 23 | enable 24 | enable 25 | 26 | 27 | 28 | none 29 | false 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | True 40 | 41 | 42 | 43 | True 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/ProviderName.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore; 7 | 8 | //TODO: Refer:(2018-12-10) https://docs.microsoft.com/en-us/ef/core/providers/index 9 | public enum ProviderName 10 | { 11 | Unknown, 12 | Cosmos, 13 | Firebird, 14 | IBM, 15 | Jet, 16 | MyCat, 17 | MySql, 18 | OpenEdge, 19 | Oracle, 20 | PostgreSQL, 21 | Sqlite, 22 | SqlServer, 23 | SqlServerCompact35, 24 | SqlServerCompact40, 25 | } 26 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Core/Scopes/UnsafeQueryScope.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using NStandard; 7 | 8 | namespace LinqSharp.EFCore.Scopes; 9 | 10 | public class UnsafeQueryScope : Scope 11 | { 12 | public class Throws 13 | { 14 | public static InvalidOperationException RunningOutsideScopeException() => new($"Unsafe operations cannot be run outside of {nameof(UnsafeQueryScope)}."); 15 | } 16 | 17 | 18 | public UnsafeQueryScope() 19 | { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/!Extensions/ModelBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace LinqSharp.EFCore; 4 | 5 | [EditorBrowsable(EditorBrowsableState.Never)] 6 | public class ModelBuilderExtensions 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Agent/KeyValueAgent.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Entities; 7 | 8 | namespace LinqSharp.EFCore.Agent; 9 | 10 | /// 11 | /// Hint: Each custom properties must be virtual(public). 12 | /// 13 | /// 14 | public abstract class KeyValueAgent 15 | where TEntity : KeyValueEntity, new() 16 | { 17 | internal bool _executed; 18 | internal KeyValueEntity[] _entities = []; 19 | 20 | internal string? _itemName; 21 | public string? GetItemName() => _itemName; 22 | } 23 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/AuditPredictor.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | using NStandard; 8 | using System.ComponentModel.DataAnnotations; 9 | 10 | namespace LinqSharp.EFCore; 11 | 12 | public class AuditPredictor 13 | { 14 | private List List { get; } = new List(); 15 | internal void Add(object auditUnit) => List.Add(auditUnit); 16 | 17 | public IEnumerable> Pick() where TEntity : class, new() 18 | { 19 | return List.OfType>(); 20 | } 21 | 22 | public TEntity[] Predict(DbSet dbSet, Func predicate) 23 | where TEntity : class, new() 24 | { 25 | var locals = Pick().Where(x => predicate(x.Current!)); 26 | var localsOfAdded = locals.Where(x => x.State == EntityState.Added).ToArray(); 27 | var localsOfModified = locals.Where(x => x.State == EntityState.Modified).ToArray(); 28 | var localsOfDeleted = locals.Where(x => x.State == EntityState.Deleted).ToArray(); 29 | var stores = dbSet.AsNoTracking().Where(predicate).ToArray(); 30 | 31 | var keyProps = typeof(TEntity).GetProperties().Where(x => x.HasAttribute()); 32 | var ret = stores.Where(store => 33 | { 34 | var ret = !localsOfModified.Any(x => keyProps.All(keyProp => keyProp.GetValue(x.Current)!.Equals(keyProp.GetValue(store)))) 35 | && !localsOfDeleted.Any(x => keyProps.All(keyProp => keyProp.GetValue(x.Current)!.Equals(keyProp.GetValue(store)))); 36 | return ret; 37 | }) 38 | .Concat(localsOfAdded.Select(x => x.Current!)) 39 | .Concat(localsOfModified.Select(x => x.Current!)) 40 | .ToArray()!; 41 | 42 | return ret; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Design/IEntity.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Design; 7 | 8 | /// 9 | /// Use to define entity classes to get some useful extension methods. 10 | /// 11 | public interface IEntity { } 12 | 13 | /// 14 | /// Use to define entity classes to get some useful extension methods. 15 | /// 16 | public interface IEntity : IEntity where TSelf : class, IEntity, new() 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Design/IEntityAuditor.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | namespace LinqSharp.EFCore.Design; 9 | 10 | public interface IEntityAuditor 11 | where TDbContext : DbContext 12 | where TEntity : class, new() 13 | { 14 | void BeforeAudit(TDbContext context, EntityAudit[] audits); 15 | void OnAuditing(TDbContext context, EntityAudit[] audits); 16 | void OnAudited(TDbContext context, AuditPredictor predictor); 17 | } 18 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Design/IZipperEntity.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore.Design; 2 | 3 | public interface IZipperEntity 4 | { 5 | public DateTime ZipperStart { get; set; } 6 | public DateTime ZipperEnd { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Entities/FieldChangeInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Entities; 7 | 8 | public class FieldChangeInfo 9 | { 10 | public string? Display { get; set; } 11 | public bool IsModified { get; set; } 12 | public object? Origin { get; set; } 13 | public object? Current { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Entities/KeyValueEntity.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Annotations; 7 | using System.ComponentModel.DataAnnotations; 8 | using System.ComponentModel.DataAnnotations.Schema; 9 | using System.Diagnostics; 10 | 11 | namespace LinqSharp.EFCore.Entities; 12 | 13 | [DebuggerDisplay("{Item}:{Key} = {Value} {(Value is not null ? (\"(\" + Value.GetType().Name + \")\") : \"\")}")] 14 | public abstract class KeyValueEntity 15 | { 16 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 17 | public Guid Id { get; set; } 18 | 19 | [Required] 20 | [IndexField(IndexType.Unique, Group = "Item&Key")] 21 | [StringLength(127)] 22 | public string? Item { get; set; } 23 | 24 | [Required] 25 | [IndexField(IndexType.Unique, Group = "Item&Key")] 26 | [StringLength(127)] 27 | public string? Key { get; set; } 28 | 29 | [StringLength(768)] 30 | public string? Value { get; set; } 31 | } 32 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Entities/RowChangeInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Utils; 7 | using Microsoft.EntityFrameworkCore.ChangeTracking; 8 | 9 | namespace LinqSharp.EFCore.Entities; 10 | 11 | public class RowChangeInfo : Dictionary 12 | { 13 | public bool IsValid { get; set; } 14 | 15 | public RowChangeInfo() { } 16 | public RowChangeInfo(IEnumerable entries) : this(entries, false) { } 17 | public RowChangeInfo(IEnumerable entries, bool modifiedOnly) 18 | { 19 | if (modifiedOnly) 20 | { 21 | entries = from entry in entries 22 | where entry.IsModified 23 | where !(entry.OriginalValue is null && entry.CurrentValue is null) && !(entry.OriginalValue?.Equals(entry.CurrentValue) ?? false) 24 | select entry; 25 | } 26 | 27 | if (entries.Any()) IsValid = true; 28 | 29 | foreach (var entry in entries) 30 | { 31 | Add(entry.Metadata.PropertyInfo!.Name, new FieldChangeInfo 32 | { 33 | Display = DataAnnotation.GetDisplayName(entry.Metadata.PropertyInfo), 34 | IsModified = entry.IsModified, 35 | Origin = entry.OriginalValue, 36 | Current = entry.CurrentValue, 37 | }); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/EntityAudit.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | using Microsoft.EntityFrameworkCore.ChangeTracking; 8 | using NStandard; 9 | 10 | namespace LinqSharp.EFCore; 11 | 12 | public static class EntityAudit 13 | { 14 | public static object Parse(EntityEntry entry) 15 | { 16 | var entity = entry.Entity; 17 | var entityType = entity.GetType(); 18 | var auditType = typeof(EntityAudit<>).MakeGenericType(entityType); 19 | 20 | var origin = Activator.CreateInstance(entityType); 21 | foreach (var originValue in entry.OriginalValues.Properties) 22 | origin.GetReflector().Property(originValue.Name).Value = entry.OriginalValues[originValue.Name]; 23 | 24 | var audit = Activator.CreateInstance(auditType)!; 25 | var auditReflector = audit.GetReflector(); 26 | auditReflector.DeclaredProperty(nameof(EntityAudit.State)).Value = entry.State; 27 | auditReflector.DeclaredProperty(nameof(EntityAudit.Origin)).Value = origin; 28 | auditReflector.DeclaredProperty(nameof(EntityAudit.Current)).Value = entity; 29 | auditReflector.DeclaredProperty(nameof(EntityAudit.PropertyEntries)).Value = entry.Properties; 30 | 31 | return audit; 32 | } 33 | } 34 | 35 | public class EntityAudit 36 | where TEntity : class, new() 37 | { 38 | public EntityState State { get; set; } 39 | public TEntity? Origin { get; set; } 40 | public TEntity? Current { get; set; } 41 | public IEnumerable? PropertyEntries { get; set; } 42 | } 43 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Infrastructure/IFacade.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Infrastructure; 7 | 8 | public interface IFacade 9 | { 10 | public bool EnableWithoutTransaction { get; } 11 | 12 | void UpdateState(); 13 | 14 | void CommitTransaction(); 15 | void RollbackTransaction(); 16 | void TransactionDisposing(); 17 | 18 | void Trigger_OnCommitted(); 19 | } 20 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Infrastructure/IFacadeState.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Infrastructure; 7 | 8 | public interface IFacadeState 9 | { 10 | bool Updated { get; } 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Infrastructure/SqlIdentifiers.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore.Infrastructure; 7 | 8 | /// 9 | /// Quoted Identifier 10 | /// 11 | public readonly struct SqlIdentifiers 12 | { 13 | public char LeftChar { get; } 14 | public char RightChar { get; } 15 | 16 | public SqlIdentifiers(char leftChar, char rightChar) 17 | { 18 | LeftChar = leftChar; 19 | RightChar = rightChar; 20 | } 21 | 22 | public SqlIdentifiers(ProviderName name) 23 | { 24 | switch (name) 25 | { 26 | case ProviderName.Cosmos: break; 27 | case ProviderName.Firebird: (LeftChar, RightChar) = ('"', '"'); break; 28 | case ProviderName.IBM: (LeftChar, RightChar) = ('"', '"'); break; 29 | case ProviderName.Jet: (LeftChar, RightChar) = ('[', ']'); break; 30 | case ProviderName.MyCat: (LeftChar, RightChar) = ('`', '`'); break; 31 | case ProviderName.MySql: (LeftChar, RightChar) = ('`', '`'); break; 32 | case ProviderName.OpenEdge: break; 33 | case ProviderName.Oracle: (LeftChar, RightChar) = ('"', '"'); break; 34 | case ProviderName.PostgreSQL: (LeftChar, RightChar) = ('"', '"'); break; 35 | case ProviderName.Sqlite: (LeftChar, RightChar) = ('"', '"'); break; 36 | case ProviderName.SqlServer: (LeftChar, RightChar) = ('[', ']'); break; 37 | case ProviderName.SqlServerCompact35: (LeftChar, RightChar) = ('[', ']'); break; 38 | case ProviderName.SqlServerCompact40: (LeftChar, RightChar) = ('[', ']'); break; 39 | case ProviderName.Unknown: break; 40 | 41 | default: throw new InvalidOperationException($"unsupported provider ({name})."); 42 | }; 43 | } 44 | 45 | public string QuoteName(string content) => $"{LeftChar}{content}{RightChar}"; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Infrastructure/Transaction.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore.Storage; 7 | 8 | namespace LinqSharp.EFCore.Infrastructure; 9 | 10 | public class Transaction : IDbContextTransaction 11 | { 12 | private readonly IFacade facade; 13 | 14 | internal Transaction(IFacade customDatabaseFacade, Guid transactionId) 15 | { 16 | facade = customDatabaseFacade; 17 | TransactionId = transactionId; 18 | } 19 | 20 | public Guid TransactionId { get; } 21 | 22 | public void Commit() => facade.CommitTransaction(); 23 | public void Rollback() => facade.RollbackTransaction(); 24 | public void Dispose() => facade.TransactionDisposing(); 25 | 26 | #if EFCORE3_1_OR_GREATER 27 | public Task CommitAsync(CancellationToken cancellationToken = default) => Task.Run(() => facade.CommitTransaction()); 28 | public Task RollbackAsync(CancellationToken cancellationToken = default) => Task.Run(() => facade.RollbackTransaction()); 29 | public ValueTask DisposeAsync() => new(Task.Run(() => facade.TransactionDisposing())); 30 | #endif 31 | 32 | } 33 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/LinqSharp.EFCore.Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bdd0d5b8-85e2-4834-9b21-6226ef90d5a8 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/LinqSharpEFRegister.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.EFCore; 7 | 8 | public static class LinqSharpEFRegister 9 | { 10 | private static readonly Dictionary BulkCopyEngineDict = new(); 11 | public static void RegisterBulkCopyEngine(ProviderName name, BulkCopyEngine? engine) => BulkCopyEngineDict[name] = engine; 12 | public static void UnregisterBulkCopyEngine(ProviderName name) => BulkCopyEngineDict.Remove(name); 13 | public static bool TryGetBulkCopyEngine(ProviderName name, out BulkCopyEngine? engine) 14 | { 15 | if (BulkCopyEngineDict.ContainsKey(name)) 16 | { 17 | engine = BulkCopyEngineDict[name]; 18 | return true; 19 | } 20 | else 21 | { 22 | engine = null; 23 | return false; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Navigation/IIncludable.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Scopes; 7 | 8 | namespace LinqSharp.EFCore.Navigation; 9 | 10 | public interface IIncludable 11 | where TEntity : class 12 | { 13 | CompoundQueryScope Owner { get; } 14 | List TargetPath { get; } 15 | } 16 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Navigation/IncludeNavigation.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Scopes; 7 | 8 | namespace LinqSharp.EFCore.Navigation; 9 | 10 | public class IncludeNavigation : IIncludable 11 | where TEntity : class 12 | where TProperty : class 13 | { 14 | public CompoundQueryScope Owner { get; } 15 | public List TargetPath { get; } 16 | 17 | internal IncludeNavigation(CompoundQueryScope owner, List targetPath) 18 | { 19 | Owner = owner; 20 | TargetPath = targetPath; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Navigation/QueryTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqSharp.EFCore.Navigation; 9 | 10 | public struct QueryTarget 11 | { 12 | public Type PreviousProperty { get; set; } 13 | public Type PreviousPropertyElement { get; set; } 14 | public Type Property { get; set; } 15 | public LambdaExpression Expression { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/PropIndex.cs: -------------------------------------------------------------------------------- 1 | using LinqSharp.EFCore.Annotations; 2 | 3 | namespace LinqSharp.EFCore; 4 | 5 | internal class PropIndex 6 | { 7 | public IndexFieldAttribute? Index { get; set; } 8 | public string? Name { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Providers/JsonProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore.ChangeTracking; 7 | using System.Reflection; 8 | #if EFCORE5_0_OR_GREATER 9 | using System.Text.Json; 10 | #else 11 | using Newtonsoft.Json; 12 | #endif 13 | 14 | namespace LinqSharp.EFCore.Providers; 15 | 16 | public static class JsonProvider 17 | { 18 | #if EFCORE5_0_OR_GREATER 19 | public static JsonSerializerOptions? DefaultOptions { get; set; } = null; 20 | #else 21 | public static JsonSerializerSettings? DefaultOptions { get; set; } = null; 22 | #endif 23 | } 24 | 25 | [AttributeUsage(AttributeTargets.Property)] 26 | public class JsonProviderAttribute : SpecialProviderAttribute 27 | { 28 | public override Attribute GetTargetProvider(PropertyInfo property) 29 | { 30 | return (Activator.CreateInstance(typeof(JsonProviderAttribute<>).MakeGenericType(property.PropertyType)) as Attribute)!; 31 | } 32 | } 33 | 34 | [AttributeUsage(AttributeTargets.Property)] 35 | public class JsonProviderAttribute : ProviderAttribute 36 | { 37 | public override TModel ReadFromProvider(string value) 38 | { 39 | #if EFCORE5_0_OR_GREATER 40 | return (JsonSerializer.Deserialize(value, JsonProvider.DefaultOptions))!; 41 | #else 42 | return (JsonConvert.DeserializeObject(value, JsonProvider.DefaultOptions))!; 43 | #endif 44 | } 45 | 46 | public override string WriteToProvider(TModel model) 47 | { 48 | #if EFCORE5_0_OR_GREATER 49 | return JsonSerializer.Serialize(model, JsonProvider.DefaultOptions); 50 | #else 51 | return JsonConvert.SerializeObject(model, JsonProvider.DefaultOptions); 52 | #endif 53 | } 54 | 55 | public override ValueComparer GetValueComparer() => GetDefaultMutableClassesComparer(); 56 | } 57 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Providers/SpecialProviderAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace LinqSharp.EFCore.Providers; 4 | 5 | public abstract class SpecialProviderAttribute : Attribute 6 | { 7 | public abstract Attribute GetTargetProvider(PropertyInfo property); 8 | } 9 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Query/UpdateOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqSharp.EFCore.Query; 9 | 10 | public class UpdateOptions where TEntity : class 11 | { 12 | public delegate void UpdateDelegate(TEntity record, TEntity entity); 13 | 14 | public UpdateDelegate? Update { get; set; } 15 | 16 | /// 17 | /// If you want to optimize the search logic, you can specify the predicate. 18 | /// (Note that the predicate must contain all possible records.) 19 | /// 20 | public Expression>? Predicate { get; set; } 21 | } 22 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Scopes/IAutoModeScope.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.EFCore.Scopes; 2 | 3 | public interface IAutoModeScope 4 | { 5 | AutoMode Mode { get; } 6 | } 7 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Scopes/RowLockScope.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | using NStandard; 8 | 9 | namespace LinqSharp.EFCore.Scopes; 10 | 11 | public sealed class RowLockScope(AutoMode option) : Scope>, IAutoModeScope 12 | where TContext : DbContext 13 | { 14 | public AutoMode Mode { get; } = option; 15 | } 16 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Scopes/TimestampScope.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | using NStandard; 8 | 9 | namespace LinqSharp.EFCore.Scopes; 10 | 11 | public sealed class TimestampScope(AutoMode mode) : Scope>, IAutoModeScope 12 | where TContext : DbContext 13 | { 14 | public AutoMode Mode { get; } = mode; 15 | } 16 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Scopes/UserTraceScope.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | using NStandard; 8 | 9 | namespace LinqSharp.EFCore.Scopes; 10 | 11 | public sealed class UserTraceScope(AutoMode mode) : Scope>, IAutoModeScope 12 | where TContext : DbContext 13 | { 14 | public AutoMode Mode { get; } = mode; 15 | } 16 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Scopes/ZipperQueryScope.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Design; 7 | using LinqSharp.EFCore.Shared.Agent; 8 | using Microsoft.EntityFrameworkCore; 9 | using NStandard; 10 | using System.Linq.Expressions; 11 | 12 | namespace LinqSharp.EFCore.Scopes; 13 | 14 | [Obsolete("Conceptual design.", false)] 15 | public sealed class ZipperQueryScope : Scope> 16 | where T : class, IZipperEntity, new() 17 | { 18 | private static readonly object _zipperlock = new(); 19 | 20 | public DbSet Source { get; } 21 | public Expression> KeySelector { get; } 22 | public Func KeySelectorFunc { get; } 23 | 24 | internal ZipperQueryScope(DbSet dbSet, Expression> keySelector) 25 | { 26 | Monitor.Enter(_zipperlock); 27 | Source = dbSet; 28 | KeySelector = keySelector; 29 | KeySelectorFunc = keySelector.Compile(); 30 | } 31 | 32 | public ZipperAgent GetAgent(TKey key) 33 | { 34 | return new ZipperAgent(Source, KeySelector, KeySelectorFunc, key); 35 | } 36 | 37 | public IEnumerable View(DateTime point) 38 | { 39 | T[] source = 40 | [ 41 | .. 42 | from x in Source 43 | where x.ZipperStart <= point && point < x.ZipperEnd 44 | select x, 45 | 46 | .. 47 | from x in Source.Local 48 | where x.ZipperStart <= point && point < x.ZipperEnd 49 | select x, 50 | ]; 51 | 52 | return 53 | from g in source 54 | .OrderBy(KeySelectorFunc).ThenBy(x => x.ZipperStart) 55 | .GroupBy(KeySelectorFunc) 56 | select g.First(); 57 | } 58 | 59 | public override void Disposing() 60 | { 61 | Monitor.Exit(_zipperlock); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /LinqSharp.EFCore/LinqSharp.EFCore.Shared/Translators/DbDouble.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.EFCore.Query; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | #if EFCORE3_1_OR_GREATER 10 | #else 11 | using SqlExpression = System.Linq.Expressions.Expression; 12 | #endif 13 | 14 | namespace LinqSharp.EFCore.Translators; 15 | 16 | public class DbDouble : Translator 17 | { 18 | public static double FromInt(int number) => number; 19 | 20 | public DbDouble() { } 21 | 22 | public override void RegisterAll(ProviderName providerName, ModelBuilder modelBuilder) 23 | { 24 | switch (providerName) 25 | { 26 | case ProviderName.MyCat: 27 | case ProviderName.MySql: 28 | MySqlRegister(this, modelBuilder); 29 | break; 30 | } 31 | } 32 | 33 | private void MySqlRegister(Translator provider, ModelBuilder modelBuilder) 34 | { 35 | provider.Register(modelBuilder, () => FromInt(default), args => 36 | { 37 | return SqlTranslator.Function("CONVERT", args[0], SqlTranslator.Fragment("DECIMAL(16, 4)")); 38 | }); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /LinqSharp.lutconfig: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | 180000 6 | -------------------------------------------------------------------------------- /LinqSharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/LinqSharp/4a32cfd975f764283b01bee83db7b8760ab4a40d/LinqSharp.png -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.AllSame.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp; 2 | 3 | public static partial class IEnumerableExtensions 4 | { 5 | public static bool AllSame(this IEnumerable enumerable) 6 | { 7 | if (!enumerable.Any()) return true; 8 | 9 | var first = enumerable.First(); 10 | foreach (var element in enumerable) 11 | { 12 | if (element is not null && first is not null) 13 | { 14 | if (!element.Equals(first)) return false; 15 | } 16 | else 17 | { 18 | if (!(element is null && first is null)) return false; 19 | } 20 | } 21 | return true; 22 | } 23 | 24 | public static bool AllSame(this IEnumerable enumerable, Func selector) 25 | { 26 | if (!enumerable.Any()) return true; 27 | 28 | var first = enumerable.First(); 29 | var firstValue = selector(first); 30 | 31 | foreach (var element in enumerable) 32 | { 33 | var selectValue = selector(element); 34 | if (selectValue is not null && firstValue is not null) 35 | { 36 | if (!selectValue.Equals(firstValue)) return false; 37 | } 38 | else 39 | { 40 | if (!(selectValue is null && firstValue is null)) return false; 41 | } 42 | } 43 | return true; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.DistinctBy.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Comparers; 7 | 8 | namespace LinqSharp; 9 | 10 | public static partial class IEnumerableExtensions 11 | { 12 | /// 13 | /// Returns distinct elements from a sequence by using a specified properties to compare values. 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | public static IEnumerable DistinctBy(this IEnumerable source, Func compare) 20 | { 21 | return Enumerable.Distinct(source, new ExactEqualityComparer(compare)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.IndexBy.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Query; 7 | 8 | namespace LinqSharp; 9 | 10 | public static partial class IEnumerableExtensions 11 | { 12 | public static IIndexing IndexBy(this IEnumerable @this, Func selector) 13 | { 14 | return new Indexing(@this, selector); 15 | } 16 | 17 | public static IUniqueIndexing UniqueIndexBy(this IEnumerable @this, Func selector) 18 | { 19 | return new UniqueIndexing(@this, selector); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.Order.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Design; 7 | 8 | namespace LinqSharp; 9 | 10 | public static partial class IEnumerableExtensions 11 | { 12 | public static IEnumerable Sort(this IEnumerable @this, ILocalSorter sorter) 13 | { 14 | var rule = sorter.Sort(); 15 | if (!rule.HasValue) return @this; 16 | 17 | var value = rule.Value; 18 | return value.Descending 19 | ? @this.OrderByDescending(value.Selector) 20 | : @this.OrderBy(value.Selector); 21 | } 22 | public static IEnumerable Sort(this IEnumerable @this, ICoLocalSorter sorter) 23 | { 24 | var enumerator = sorter.Sort().GetEnumerator(); 25 | if (enumerator.MoveNext()) 26 | { 27 | var rule = enumerator.Current; 28 | var ordered = rule.Descending 29 | ? @this.OrderByDescending(rule.Selector) 30 | : @this.OrderBy(rule.Selector); 31 | 32 | while (enumerator.MoveNext()) 33 | { 34 | rule = enumerator.Current; 35 | ordered = rule.Descending 36 | ? ordered.ThenByDescending(rule.Selector) 37 | : ordered.ThenBy(rule.Selector); 38 | } 39 | return ordered; 40 | } 41 | return @this; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.OrderByCase.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Strategies; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp; 10 | 11 | public static partial class IEnumerableExtensions 12 | { 13 | public static IOrderedEnumerable OrderByCase(this IEnumerable @this, 14 | Expression> memberExp, 15 | TRet[] orderValues) 16 | { 17 | return @this.OrderBy(new OrderByCaseStrategy(memberExp, orderValues).StrategyExpression.Compile()); 18 | } 19 | 20 | public static IOrderedEnumerable OrderByCaseDescending(this IEnumerable @this, 21 | Expression> memberExp, 22 | TRet[] orderValues) 23 | { 24 | return @this.OrderByDescending(new OrderByCaseStrategy(memberExp, orderValues).StrategyExpression.Compile()); 25 | } 26 | 27 | public static IOrderedEnumerable ThenByCase(this IOrderedEnumerable @this, 28 | Expression> memberExp, 29 | TRet[] orderValues) 30 | { 31 | return @this.ThenBy(new OrderByCaseStrategy(memberExp, orderValues).StrategyExpression.Compile()); 32 | } 33 | 34 | public static IOrderedEnumerable ThenByCaseDescending(this IOrderedEnumerable @this, 35 | Expression> memberExp, 36 | TRet[] orderValues) 37 | { 38 | return @this.ThenByDescending(new OrderByCaseStrategy(memberExp, orderValues).StrategyExpression.Compile()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.Random.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp; 7 | 8 | public static partial class IEnumerableExtensions 9 | { 10 | /// 11 | /// Select the specified number of random record from a source set. 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | public static IEnumerable Random(this IEnumerable @this, int takeCount) 18 | { 19 | return @this.OrderBy(x => Guid.NewGuid()).Take(takeCount); 20 | } 21 | 22 | /// 23 | /// Get a random record from a source set. 24 | /// 25 | /// 26 | /// 27 | /// 28 | public static TSource Random(this IEnumerable @this) 29 | { 30 | return @this.OrderBy(x => Guid.NewGuid()).Take(1).First(); 31 | } 32 | 33 | /// 34 | /// Get a random record from a source set. 35 | /// 36 | /// 37 | /// 38 | /// 39 | public static TSource? RandomOrDefault(this IEnumerable @this) 40 | { 41 | return @this.OrderBy(x => Guid.NewGuid()).Take(1).FirstOrDefault(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.Repeat.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp; 7 | 8 | public static partial class IEnumerableExtensions 9 | { 10 | public static IEnumerable Repeat(this IEnumerable source, int repeats) 11 | { 12 | foreach (var item in source) 13 | { 14 | for (int i = 0; i < repeats; i++) 15 | { 16 | yield return item; 17 | } 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.Same.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp; 2 | 3 | public static partial class IEnumerableExtensions 4 | { 5 | public static TSource Same(this IEnumerable enumerable) 6 | { 7 | if (!enumerable.Any()) return default!; 8 | 9 | var first = enumerable.First(); 10 | foreach (var element in enumerable) 11 | { 12 | if (element is not null && first is not null) 13 | { 14 | if (!element.Equals(first)) throw new InvalidOperationException($"{first} and {element} are not same."); 15 | } 16 | else 17 | { 18 | if (!(element is null && first is null)) throw new InvalidOperationException($"{first} and {element} are not same."); 19 | } 20 | } 21 | return first; 22 | } 23 | 24 | public static TResult Same(this IEnumerable enumerable, Func selector) 25 | { 26 | if (!enumerable.Any()) return default!; 27 | 28 | var first = enumerable.First(); 29 | var firstValue = selector(first); 30 | 31 | foreach (var element in enumerable) 32 | { 33 | var selectValue = selector(element); 34 | if (selectValue is not null && firstValue is not null) 35 | { 36 | if (!selectValue.Equals(firstValue)) throw new InvalidOperationException($"{firstValue} and {selectValue} are not same."); 37 | } 38 | else 39 | { 40 | if (!(selectValue is null && firstValue is null)) throw new InvalidOperationException($"{firstValue} and {selectValue} are not same."); 41 | } 42 | } 43 | return firstValue; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.SameOrDefault.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp; 2 | 3 | public static partial class IEnumerableExtensions 4 | { 5 | public static TSource? SameOrDefault(this IEnumerable enumerable) 6 | { 7 | if (!enumerable.Any()) return default; 8 | 9 | var first = enumerable.First(); 10 | foreach (var element in enumerable) 11 | { 12 | if (element is not null && first is not null) 13 | { 14 | if (!element.Equals(first)) return default; 15 | } 16 | else 17 | { 18 | if (!(element is null && first is null)) return default; 19 | } 20 | } 21 | return first; 22 | } 23 | 24 | public static TResult? SameOrDefault(this IEnumerable enumerable, Func selector) 25 | { 26 | if (!enumerable.Any()) return default; 27 | 28 | var first = enumerable.First(); 29 | var firstValue = selector(first); 30 | 31 | foreach (var element in enumerable) 32 | { 33 | var selectValue = selector(element); 34 | if (selectValue is not null && firstValue is not null) 35 | { 36 | if (!selectValue.Equals(firstValue)) return default; 37 | } 38 | else 39 | { 40 | if (!(selectValue is null && firstValue is null)) return default; 41 | } 42 | } 43 | return firstValue; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.Search.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Filters; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp; 10 | 11 | public static partial class IEnumerableExtensions 12 | { 13 | public static IEnumerable Search(this IEnumerable @this, SearchMode mode, string search, Expression> selector) 14 | { 15 | return @this.Filter(new SearchFilter(mode, [search], selector)); 16 | } 17 | 18 | public static IEnumerable Search(this IEnumerable @this, SearchMode mode, string[] searches, Expression> selector) 19 | { 20 | return @this.Filter(new SearchFilter(mode, searches, selector)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.SelectMore.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp; 7 | 8 | public static partial class IEnumerableExtensions 9 | { 10 | public static IEnumerable SelectMore(this IEnumerable @this, Func> childrenSelector) 11 | { 12 | return SelectMore(@this, childrenSelector, null); 13 | } 14 | 15 | public static IEnumerable SelectMore(this IEnumerable @this, Func> childrenSelector, Func? predicate) 16 | { 17 | IEnumerable RecursiveChildren(TSource node) 18 | { 19 | if (predicate?.Invoke(node) ?? true) 20 | yield return node; 21 | 22 | var selectNode = childrenSelector(node)!; 23 | if (selectNode?.Any() ?? false) 24 | { 25 | var children = selectNode.SelectMany(x => RecursiveChildren(x)); 26 | foreach (var child in children) 27 | { 28 | if (predicate?.Invoke(node) ?? true) 29 | yield return child; 30 | } 31 | } 32 | } 33 | 34 | var ret = @this.SelectMany(RecursiveChildren)!; 35 | return ret; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.SelectUntil.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp; 7 | 8 | public static partial class IEnumerableExtensions 9 | { 10 | public static IEnumerable SelectUntil(this IEnumerable @this, Func> childrenSelector, Func predicate) 11 | { 12 | IEnumerable RecursiveChildren(TSource node) 13 | { 14 | var selectNode = childrenSelector(node); 15 | if (predicate(node)) 16 | yield return node; 17 | else 18 | { 19 | if (selectNode?.Any() ?? false) 20 | { 21 | var children = selectNode.SelectMany(x => RecursiveChildren(x)); 22 | foreach (var child in children) 23 | yield return child; 24 | } 25 | } 26 | } 27 | 28 | var ret = @this.SelectMany(x => RecursiveChildren(x)); 29 | return ret; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.SelectWhile.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp; 7 | 8 | public static partial class IEnumerableExtensions 9 | { 10 | public static IEnumerable SelectWhile(this IEnumerable @this, Func> childrenSelector, Func predicate) 11 | { 12 | IEnumerable RecursiveChildren(TSource node) 13 | { 14 | var selectNode = childrenSelector(node); 15 | if (predicate(node)) 16 | { 17 | yield return node; 18 | 19 | if (selectNode?.Any() ?? false) 20 | { 21 | var children = selectNode.SelectMany(x => RecursiveChildren(x)); 22 | foreach (var child in children) 23 | yield return child; 24 | } 25 | } 26 | } 27 | 28 | var ret = @this.SelectMany(x => RecursiveChildren(x)); 29 | return ret; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.Tile.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp; 7 | 8 | public static partial class IEnumerableExtensions 9 | { 10 | public static IEnumerable Tile(this IEnumerable source, int repeats) 11 | { 12 | for (int i = 0; i < repeats; i++) 13 | { 14 | foreach (var item in source) 15 | { 16 | yield return item; 17 | } 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IEnumerable/IEnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.ComponentModel; 7 | 8 | namespace LinqSharp; 9 | 10 | [EditorBrowsable(EditorBrowsableState.Never)] 11 | public static partial class IEnumerableExtensions 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IQueryable/IQueryableExtensions.MaxOrDefault.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqSharp; 9 | 10 | public static partial class IQueryableExtensions 11 | { 12 | public static TResult? MaxOrDefault(this IQueryable source, Expression> selector, TResult? @default = default) => source.Any() ? source.Max(selector) : @default; 13 | public static TSource? MaxOrDefault(this IQueryable source, TSource? @default = default) => source.Any() ? source.Max() : @default; 14 | } 15 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IQueryable/IQueryableExtensions.MinOrDefault.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqSharp; 9 | 10 | public static partial class IQueryableExtensions 11 | { 12 | public static TResult? MinOrDefault(this IQueryable source, Expression> selector, TResult? @default = default) => source.Any() ? source.Min(selector) : @default; 13 | public static TSource? MinOrDefault(this IQueryable source, TSource? @default = default) => source.Any() ? source.Min() : @default; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IQueryable/IQueryableExtensions.Order.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Design; 7 | 8 | namespace LinqSharp; 9 | 10 | public static partial class IQueryableExtensions 11 | { 12 | public static IQueryable Sort(this IQueryable @this, IQuerySorter sorter) 13 | { 14 | var rule = sorter.Sort(); 15 | if (!rule.HasValue) return @this; 16 | 17 | var value = rule.Value; 18 | return value.Descending 19 | ? @this.OrderByDescending(value.Selector) 20 | : @this.OrderBy(value.Selector); 21 | } 22 | public static IQueryable Sort(this IQueryable @this, ICoQuerySorter sorter) 23 | { 24 | var enumerator = sorter.Sort().GetEnumerator(); 25 | if (enumerator.MoveNext()) 26 | { 27 | var rule = enumerator.Current; 28 | var ordered = rule.Descending 29 | ? @this.OrderByDescending(rule.Selector) 30 | : @this.OrderBy(rule.Selector); 31 | 32 | while (enumerator.MoveNext()) 33 | { 34 | rule = enumerator.Current; 35 | ordered = rule.Descending 36 | ? ordered.ThenByDescending(rule.Selector) 37 | : ordered.ThenBy(rule.Selector); 38 | } 39 | return ordered; 40 | } 41 | return @this; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IQueryable/IQueryableExtensions.OrderByCase.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Strategies; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp; 10 | 11 | public static partial class IQueryableExtensions 12 | { 13 | public static IOrderedQueryable OrderByCase(this IQueryable @this, 14 | Expression> memberExp, 15 | TRet[] orderValues) 16 | { 17 | return @this.OrderBy(new OrderByCaseStrategy(memberExp, orderValues).StrategyExpression); 18 | } 19 | 20 | public static IOrderedQueryable OrderByCaseDescending(this IQueryable @this, 21 | Expression> memberExp, 22 | TRet[] orderValues) 23 | { 24 | return @this.OrderByDescending(new OrderByCaseStrategy(memberExp, orderValues).StrategyExpression); 25 | } 26 | 27 | public static IOrderedQueryable ThenByCase(this IOrderedQueryable @this, 28 | Expression> memberExp, 29 | TRet[] orderValues) 30 | { 31 | return @this.ThenBy(new OrderByCaseStrategy(memberExp, orderValues).StrategyExpression); 32 | } 33 | 34 | public static IOrderedQueryable ThenByCaseDescending(this IOrderedQueryable @this, 35 | Expression> memberExp, 36 | TRet[] orderValues) 37 | { 38 | return @this.ThenByDescending(new OrderByCaseStrategy(memberExp, orderValues).StrategyExpression); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IQueryable/IQueryableExtensions.Search.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Filters; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp; 10 | 11 | public static partial class IQueryableExtensions 12 | { 13 | public static IQueryable Search(this IQueryable @this, SearchMode mode, string search, Expression> selector) 14 | { 15 | return Search(@this, mode, [search], selector); 16 | } 17 | 18 | public static IQueryable Search(this IQueryable @this, SearchMode mode, string[] searches, Expression> selector) 19 | { 20 | return @this.Filter(new SearchFilter(mode, searches, selector)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IQueryable/IQueryableExtensions.WhereMax.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Design; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp; 10 | 11 | public static partial class IQueryableExtensions 12 | { 13 | public static IQueryable WhereMax(this IQueryable sources, Expression> selector) 14 | { 15 | return sources.Filter(h => 16 | { 17 | if (sources.Any()) 18 | { 19 | var min = sources.Max(selector); 20 | var whereExp = Expression.Lambda>( 21 | Expression.Equal(selector.Body, Expression.Constant(min, typeof(TResult))), selector.Parameters); 22 | return new QueryExpression(whereExp); 23 | } 24 | else return new QueryExpression(x => false); 25 | }); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IQueryable/IQueryableExtensions.WhereMin.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Design; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp; 10 | 11 | public static partial class IQueryableExtensions 12 | { 13 | public static IQueryable WhereMin(this IQueryable sources, Expression> selector) 14 | { 15 | return sources.Filter(h => 16 | { 17 | if (sources.Any()) 18 | { 19 | var min = sources.Min(selector); 20 | var whereExp = Expression.Lambda>( 21 | Expression.Equal(selector.Body, Expression.Constant(min, typeof(TResult))), selector.Parameters); 22 | return new QueryExpression(whereExp); 23 | } 24 | else return new QueryExpression(x => false); 25 | }); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/!IQueryable/IQueryableExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.ComponentModel; 7 | 8 | namespace LinqSharp; 9 | 10 | [EditorBrowsable(EditorBrowsableState.Never)] 11 | public static partial class IQueryableExtensions 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /LinqSharp/!Extensions/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using LinqSharp.Utils; 7 | using System.ComponentModel; 8 | 9 | namespace LinqSharp; 10 | 11 | [EditorBrowsable(EditorBrowsableState.Never)] 12 | public static class EnumExtensions 13 | { 14 | public static string? DisplayName(this Enum @this) 15 | { 16 | var field = @this.GetType().GetFields().First(x => x.Name == @this.ToString()); 17 | return DataAnnotation.GetDisplayName(field); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /LinqSharp/!Internal/MethodAccessor.Object.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | // 7 | using NStandard; 8 | using System.Reflection; 9 | 10 | namespace LinqSharp; 11 | 12 | internal static partial class MethodAccessor 13 | { 14 | internal class Object 15 | { 16 | internal static MethodInfo ToStringMethod => lazy_ToStringMethod.Value; 17 | /// 18 | /// Method: System.String ToString() 19 | /// 20 | private static readonly Lazy lazy_ToStringMethod = new(() => 21 | { 22 | return typeof(object) 23 | .GetMethodViaQualifiedName( 24 | "System.String ToString()", 25 | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance 26 | ); 27 | }); 28 | 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /LinqSharp/!Internal/MethodAccessor.Object.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="false" language="C#" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ import namespace="System.Linq" #> 4 | <#@ import namespace="System.Text" #> 5 | <#@ import namespace="System.Collections.Generic" #> 6 | <#@ output extension=".cs" #> 7 | // Copyright 2020 zmjack 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // See the LICENSE file in the project root for more information. 11 | 12 | // 13 | using NStandard; 14 | using System.Reflection; 15 | 16 | namespace LinqSharp; 17 | 18 | internal static partial class MethodAccessor 19 | { 20 | internal class <#=className#> 21 | { 22 | <# 23 | foreach(var item in _dict) 24 | { 25 | #> 26 | internal static MethodInfo <#=item.Key#> => lazy_<#=item.Key#>.Value; 27 | /// 28 | /// Method: <#=item.Value.QualifiedName#> 29 | /// 30 | private static readonly Lazy lazy_<#=item.Key#> = new(() => 31 | { 32 | return typeof(<#=item.Value.Type#>) 33 | .GetMethodViaQualifiedName( 34 | "<#=item.Value.QualifiedName#>", 35 | <#=item.Value.Flags#> 36 | ); 37 | }); 38 | 39 | <# 40 | } 41 | #> 42 | } 43 | } 44 | 45 | <#+ 46 | private string className = "Object"; 47 | 48 | private readonly Dictionary _dict = new() 49 | { 50 | ["ToStringMethod"] = ( 51 | "object", 52 | "BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance", 53 | "System.String ToString()" 54 | ), 55 | }; 56 | #> -------------------------------------------------------------------------------- /LinqSharp/Comparers/SequenceComparer.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.Comparers; 2 | 3 | public class SequenceComparer : IEqualityComparer> 4 | { 5 | public SequenceComparer() 6 | { 7 | } 8 | 9 | public bool Equals(IEnumerable? x, IEnumerable? y) 10 | { 11 | if (x is null) return y is null; 12 | if (y is null) return false; 13 | return x.SequenceEqual(y); 14 | } 15 | 16 | public int GetHashCode(IEnumerable obj) 17 | { 18 | return obj.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /LinqSharp/Design/!FieldFilter/ICoFieldFilter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design; 7 | 8 | public interface ICoFieldFilter 9 | { 10 | IEnumerable> Filter(QueryHelper h); 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Design/!FieldFilter/IFieldFilter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design; 7 | 8 | public interface IFieldFilter 9 | { 10 | QueryExpression Filter(QueryHelper h); 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Design/!Filter/ILocalFilter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design; 7 | 8 | public interface ILocalFilter 9 | { 10 | IEnumerable Apply(IEnumerable source); 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Design/!Filter/IQueryFilter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design; 7 | 8 | public interface IQueryFilter 9 | { 10 | IQueryable Apply(IQueryable source); 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Design/!Sorter/ICoLocalSorter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design; 7 | 8 | public interface ICoLocalSorter 9 | { 10 | IEnumerable> Sort(); 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Design/!Sorter/ICoQuerySorter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design; 7 | 8 | public interface ICoQuerySorter 9 | { 10 | IEnumerable> Sort(); 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Design/!Sorter/ILocalSorter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design; 7 | 8 | public interface ILocalSorter 9 | { 10 | LocalSortRule? Sort(); 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Design/!Sorter/IQuerySorter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design; 7 | 8 | public interface IQuerySorter 9 | { 10 | QuerySortRule? Sort(); 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Design/!Sorter/LocalSortRule.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.Design; 2 | 3 | public struct LocalSortRule(Func selector, bool descending = false) 4 | { 5 | public Func Selector { get; set; } = selector; 6 | public bool Descending { get; set; } = descending; 7 | } 8 | -------------------------------------------------------------------------------- /LinqSharp/Design/!Sorter/QuerySortRule.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace LinqSharp.Design; 4 | 5 | public struct QuerySortRule(Expression> selector, bool descending = false) 6 | { 7 | public Expression> Selector { get; set; } = selector; 8 | public bool Descending { get; set; } = descending; 9 | } 10 | -------------------------------------------------------------------------------- /LinqSharp/Design/ISummable.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Design 7 | { 8 | public interface ISummable 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/PadDirection.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp; 7 | 8 | public enum PadDirection 9 | { 10 | Default, 11 | Left, 12 | Right, 13 | } 14 | -------------------------------------------------------------------------------- /LinqSharp/Query/EnumerablePage.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Collections; 7 | 8 | namespace LinqSharp.Query; 9 | 10 | public class EnumerablePage : IEnumerablePage 11 | { 12 | public IEnumerable Items { get; protected set; } 13 | public int PageNumber { get; protected set; } 14 | public int PageSize { get; protected set; } 15 | public int PageCount { get; protected set; } 16 | public int SourceCount { get; protected set; } 17 | public bool IsFristPage => PageNumber == 1; 18 | public bool IsLastPage => PageNumber == PageCount; 19 | 20 | public EnumerablePage(IEnumerable source, int page, int pageSize) 21 | { 22 | if (page < 1) throw new ArgumentException("Page must be greater than 0."); 23 | if (pageSize < 1) throw new ArgumentException("Page must be greater than 0."); 24 | 25 | PageSize = pageSize; 26 | PageCount = source.PageCount(pageSize, out var sourceCount); 27 | SourceCount = sourceCount; 28 | PageNumber = page; 29 | Items = source.Skip((PageNumber - 1) * PageSize).Take(PageSize); 30 | } 31 | 32 | public EnumerablePage(QueryablePage pagedQueryable) 33 | { 34 | PageSize = pagedQueryable.PageSize; 35 | PageCount = pagedQueryable.PageCount; 36 | PageNumber = pagedQueryable.PageNumber; 37 | SourceCount = pagedQueryable.SourceCount; 38 | Items = pagedQueryable.ToArray(); 39 | } 40 | 41 | public IEnumerator GetEnumerator() => Items.GetEnumerator(); 42 | IEnumerator IEnumerable.GetEnumerator() => Items.GetEnumerator(); 43 | } 44 | -------------------------------------------------------------------------------- /LinqSharp/Query/IEnumerablePage.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Collections; 7 | 8 | namespace LinqSharp.Query; 9 | 10 | public interface IEnumerablePage : IEnumerable 11 | { 12 | int PageNumber { get; } 13 | int PageSize { get; } 14 | int PageCount { get; } 15 | int SourceCount { get; } 16 | bool IsFristPage { get; } 17 | bool IsLastPage { get; } 18 | } 19 | 20 | public interface IEnumerablePage : IEnumerablePage, IEnumerable 21 | { 22 | IEnumerable Items { get; } 23 | } 24 | -------------------------------------------------------------------------------- /LinqSharp/Query/IIndexing.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Query; 7 | 8 | public interface IIndexing : IDictionary> 9 | { 10 | IEnumerable AllValues { get; } 11 | } 12 | -------------------------------------------------------------------------------- /LinqSharp/Query/IJoinResult.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.Query; 2 | 3 | public interface IJoinResult 4 | { 5 | TLeft Left { get; set; } 6 | TRight Right { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /LinqSharp/Query/IQueryablePage.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Query; 7 | 8 | public interface IQueryablePage : IEnumerablePage, IQueryable 9 | { 10 | } 11 | 12 | public interface IQueryablePage : IEnumerablePage, IQueryable 13 | { 14 | } 15 | 16 | -------------------------------------------------------------------------------- /LinqSharp/Query/IUniqueIndexing.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using NStandard; 7 | 8 | namespace LinqSharp.Query; 9 | 10 | public interface IUniqueIndexing : IDictionary?> 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /LinqSharp/Query/JoinResult.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp.Query; 2 | 3 | public struct JoinResult : IJoinResult 4 | { 5 | public TLeft Left { get; set; } 6 | public TRight Right { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /LinqSharp/Query/QueryablePage.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Collections; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp.Query; 10 | 11 | public class QueryablePage : IQueryablePage 12 | { 13 | public IEnumerable Items { get; protected set; } 14 | public int PageNumber { get; protected set; } 15 | public int PageSize { get; protected set; } 16 | public int PageCount { get; protected set; } 17 | public int SourceCount { get; protected set; } 18 | public bool IsFristPage => PageNumber == 1; 19 | public bool IsLastPage => PageNumber == PageCount; 20 | 21 | public Type ElementType => (Items as IQueryable)!.ElementType; 22 | public Expression Expression => (Items as IQueryable)!.Expression; 23 | public IQueryProvider Provider => (Items as IQueryable)!.Provider; 24 | 25 | public QueryablePage(IQueryable source, int page, int pageSize) 26 | { 27 | if (page < 1) throw new ArgumentException("Page must be greater than 0."); 28 | if (pageSize < 1) throw new ArgumentException("PageSize must be greater than 0."); 29 | 30 | PageSize = pageSize; 31 | PageCount = source.PageCount(pageSize, out var sourceCount); 32 | SourceCount = sourceCount; 33 | PageNumber = page; 34 | Items = source.Skip((PageNumber - 1) * PageSize).Take(PageSize); 35 | } 36 | 37 | public EnumerablePage ToEnumerable() => new(this); 38 | 39 | public IEnumerator GetEnumerator() => Items.GetEnumerator(); 40 | IEnumerator IEnumerable.GetEnumerator() => Items.GetEnumerator(); 41 | } 42 | -------------------------------------------------------------------------------- /LinqSharp/SearchMode.cs: -------------------------------------------------------------------------------- 1 | namespace LinqSharp; 2 | 3 | public enum SearchMode 4 | { 5 | Default, 6 | Contains, 7 | Equals, 8 | NotContains, 9 | NotEquals, 10 | } 11 | -------------------------------------------------------------------------------- /LinqSharp/SearchSelector.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace LinqSharp; 4 | 5 | public class SearchSelector : IEnumerable 6 | { 7 | public void Add(object expression) 8 | { 9 | throw new NotImplementedException(); 10 | } 11 | 12 | public IEnumerator GetEnumerator() 13 | { 14 | throw new NotImplementedException(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LinqSharp/Strategies/IQueryStrategy.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqSharp.Strategies; 9 | 10 | public interface IQueryStrategy 11 | { 12 | Expression>? StrategyExpression { get; } 13 | } 14 | -------------------------------------------------------------------------------- /LinqSharp/Strategies/OrderByCaseStrategy.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using NStandard; 7 | using System.Linq.Expressions; 8 | 9 | namespace LinqSharp.Strategies; 10 | 11 | public class OrderByCaseStrategy : IQueryStrategy 12 | { 13 | public Expression> StrategyExpression { get; } 14 | 15 | public OrderByCaseStrategy( 16 | Expression> memberExp, 17 | TRet[] orderValues) 18 | { 19 | var valueLength = orderValues.Length; 20 | var lambdaExp = orderValues.Reverse().Pairs().Aggregate(null as Expression, (acc, pair) => 21 | { 22 | var (index, value) = pair; 23 | var compareExp = Expression.Equal(memberExp.Body, Expression.Constant(value)); 24 | 25 | if (acc is null) 26 | { 27 | return 28 | Expression.Condition( 29 | compareExp, 30 | Expression.Constant(valueLength - 1 - index), 31 | Expression.Constant(valueLength)); 32 | } 33 | else 34 | { 35 | return 36 | Expression.Condition( 37 | compareExp, 38 | Expression.Constant(valueLength - 1 - index), 39 | acc); 40 | } 41 | }) ?? Expression.Constant(0); 42 | 43 | StrategyExpression = Expression.Lambda>(lambdaExp, memberExp.Parameters); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /LinqSharp/Utils/ExpressionRebinder.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqSharp.Utils; 9 | 10 | public class ExpressionRebinder : ExpressionVisitor 11 | { 12 | private readonly Expression _from, _to; 13 | public ExpressionRebinder(Expression from, Expression to) 14 | { 15 | _from = from; 16 | _to = to; 17 | } 18 | 19 | public override Expression? Visit(Expression? node) => node == _from ? _to : base.Visit(node); 20 | } 21 | -------------------------------------------------------------------------------- /LinqSharp/Utils/ExpressionRewriter.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqSharp.Utils; 9 | 10 | [Obsolete("Designing...")] 11 | public class ExpressionRewriter 12 | { 13 | public class Visitor : ExpressionVisitor 14 | { 15 | public Expression _root; 16 | public Dictionary _rules; 17 | 18 | internal Visitor(Expression root, Dictionary rules) 19 | { 20 | _root = root; 21 | _rules = rules; 22 | } 23 | 24 | public override Expression? Visit(Expression? node) 25 | { 26 | if (node is null) return null; 27 | 28 | foreach (var pair in _rules) 29 | { 30 | if (pair.Key(_root, node)) 31 | { 32 | return pair.Value; 33 | } 34 | } 35 | return base.Visit(node); 36 | } 37 | } 38 | 39 | public delegate bool RuleDelegate(Expression root, Expression node); 40 | 41 | private readonly Dictionary _rules = []; 42 | 43 | public ExpressionRewriter() 44 | { 45 | } 46 | 47 | public Expression this[RuleDelegate key] 48 | { 49 | set => _rules[key] = value; 50 | } 51 | 52 | public void Add(Func key, Expression value) 53 | { 54 | ((IDictionary, Expression>)_rules).Add(key, value); 55 | } 56 | 57 | public void Clear() 58 | { 59 | _rules.Clear(); 60 | } 61 | 62 | public Expression? Build(Expression node) 63 | { 64 | var visitor = new Visitor(node, _rules); 65 | return visitor.Visit(node); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /LinqSharp/Utils/PropertyExplorer.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using System.Linq.Expressions; 7 | using System.Reflection; 8 | 9 | namespace LinqSharp.Utils; 10 | 11 | public static class PropertyExplorer 12 | { 13 | public static string[] GetNames(Expression> keys) 14 | { 15 | string[] propNames; 16 | switch (keys.Body) 17 | { 18 | case MemberExpression exp: 19 | propNames = [exp.Member.Name]; 20 | break; 21 | 22 | case NewExpression exp: 23 | propNames = exp.Members!.Select(x => x.Name).ToArray(); 24 | break; 25 | 26 | case UnaryExpression exp: 27 | if (exp.NodeType == ExpressionType.Convert) 28 | { 29 | var mexp = exp.Operand as MemberExpression; 30 | if (mexp is not null) 31 | { 32 | propNames = [mexp.Member.Name]; 33 | break; 34 | } 35 | else goto default; 36 | } 37 | else goto default; 38 | 39 | default: 40 | throw new NotSupportedException("This argument must be MemberExpression or NewExpression."); 41 | } 42 | 43 | return propNames; 44 | } 45 | 46 | public static IEnumerable GetProperties(Expression> keys) 47 | { 48 | var propNames = GetNames(keys); 49 | var type = typeof(TEntity); 50 | var props = type.GetProperties().Where(x => propNames.Contains(x.Name)); 51 | return props; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /docs/cn/ef-agent-query.md: -------------------------------------------------------------------------------- 1 | ## 用于 Key-Value 的代理查询 2 | 3 | 代理查询(**Agent Query**)属于动态查询的特殊构建方式。 4 | 5 | 它可以将特定实体(**Entity**)的每个属性映射为对数据行(**Row**)的访问,可用于对 **Key-Value** 存储结构的便捷访问。 6 | 7 |
8 | 9 | ### 示例 10 | 11 | 1. 定义 **Key-Value** 表实体 **AppRegistryEntity**: 12 | 13 | ```csharp 14 | public class AppRegistryEntity : KeyValueEntity { } 15 | ``` 16 | ```csharp 17 | public class ApplicationDbContext : DbContext 18 | { 19 | public DbSet AppRegistries { get; set; } 20 | } 21 | ``` 22 | 2. 定义代理实体 **AppRegistry**: 23 | 24 | ```csharp 25 | public class AppRegistry : KeyValueAgent 26 | { 27 | public virtual string Theme { get; set; } = "Default"; 28 | public virtual string Color { get; set; } 29 | 30 | public virtual int Volume { get; set; } 31 | public virtual DateTime? LoginTime { get; set; } 32 | 33 | public virtual bool Lock { get; set; } 34 | } 35 | ``` 36 | 3. 查询操作 37 | 38 | ```csharp 39 | using (var context = ApplicationDbContext.UseMySql()) 40 | using (var query = context.BeginAgentQuery(x => x.AppRegistries)) 41 | { 42 | var jerry = query.GetAgent("/User/Jerry"); 43 | 44 | jerry.Theme = "Sky"; 45 | jerry.Color = "brown"; 46 | jerry.Volume = 10; 47 | jerry.LoginTime = now; 48 | jerry.Lock = true; 49 | 50 | context.SaveChanges(); 51 | } 52 | ``` 53 | 4. 执行结果 54 | 55 | | Id | Item | Key | Value | 56 | | -------- | ----------- | ------------- | ----------------- | 57 | | \ | /User/Jerry | **Theme** | Sky | 58 | | \ | /User/Jerry | **Color** | brown | 59 | | \ | /User/Jerry | **Volume** | 10 | 60 | | \ | /User/Jerry | **LoginTime** | 2023/1/1 15:00:00 | 61 | | \ | /User/Jerry | **Lock** | True | -------------------------------------------------------------------------------- /docs/cn/ef-calc-functions.md: -------------------------------------------------------------------------------- 1 | ## 计算函数 2 | 3 | **LinqSharp.EFCore** 为数据操作提供了更多计算函数: 4 | 5 | - 字符串连接(**Concat**) 6 | - 构建日期(**DateTime**) 7 | - 随机数(**Random**) 8 | 9 | | Calculation Function | Firebird | IBM | MySql | Oracle | PostgreSQL | SqlServer | 10 | | -------------------- | :------: | :--: | :---: | :----: | :--------: | :-------: | 11 | | DbFunc.**Concat** | 🔘 | 🔘 | ✔️ | ✔️ | ✔️ | ✔️ | 12 | | DbFunc.**DateTime** | 🔘 | 🔘 | ✔️ | 🔘 | 🔘 | ✔️ | 13 | | DbFunc.**Random** | 🔘 | 🔘 | ✔️ | ✔️ | ✔️ | ✔️ | 14 | 15 | | Direct Action | Jet | Sqlite | SqlServer
Compact35 | SqlServer
Compact40 | 16 | | ------------------- | :--: | :----: | :----------------------: | :----------------------: | 17 | | DbFunc.**Concat** | ❌ | ❌ | ✔️ | ✔️ | 18 | | DbFunc.**DateTime** | ❌ | ❌ | ✔️ | ✔️ | 19 | | DbFunc.**Random** | ✔️ | ✔️ | ✔️ | ✔️ | 20 | 21 |
22 | 23 | -------------------------------------------------------------------------------- /docs/images/compound-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/LinqSharp/4a32cfd975f764283b01bee83db7b8760ab4a40d/docs/images/compound-query.png -------------------------------------------------------------------------------- /docs/images/employee-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/LinqSharp/4a32cfd975f764283b01bee83db7b8760ab4a40d/docs/images/employee-tree.png -------------------------------------------------------------------------------- /docs/images/select-more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/LinqSharp/4a32cfd975f764283b01bee83db7b8760ab4a40d/docs/images/select-more.png -------------------------------------------------------------------------------- /docs/images/select-until.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/LinqSharp/4a32cfd975f764283b01bee83db7b8760ab4a40d/docs/images/select-until.png -------------------------------------------------------------------------------- /docs/images/select-while.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/LinqSharp/4a32cfd975f764283b01bee83db7b8760ab4a40d/docs/images/select-while.png -------------------------------------------------------------------------------- /dotnet-orm/DbTable.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Cli 7 | { 8 | public class DbTable 9 | { 10 | public string Name { get; set; } 11 | public string DisplayName { get; set; } 12 | public DbTableField[] TableFields { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /dotnet-orm/DbTableField.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | namespace LinqSharp.Cli 7 | { 8 | public class DbTableField 9 | { 10 | public string Name { get; set; } 11 | public string DisplayName { get; set; } 12 | public Type RuntimeType { get; set; } 13 | public int? MaxLength { get; set; } 14 | public string Index { get; set; } 15 | public bool Required { get; set; } 16 | public Type ReferenceType { get; set; } 17 | public string ObsoleteLevel { get; set; } 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dotnet-orm/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 zmjack 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // See the LICENSE file in the project root for more information. 5 | 6 | using DotNetCli; 7 | using NStandard; 8 | using System.Reflection; 9 | 10 | namespace LinqSharp.Cli 11 | { 12 | public class Program 13 | { 14 | public static readonly string CLI_VERSION = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 15 | public static CmdContainer CmdContainer; 16 | public static Project ProjectInfo { get; private set; } 17 | 18 | static void Main(string[] args) 19 | { 20 | CmdContainer = new CmdContainer("orm", Assembly.GetExecutingAssembly(), Project.GetFromDirectory(Directory.GetCurrentDirectory())); 21 | if (CmdContainer.Project.HasValue) 22 | { 23 | ProjectInfo = CmdContainer.Project.Value; 24 | } 25 | else throw new InvalidOperationException("No project found."); 26 | 27 | PrintWelcome(); 28 | 29 | CmdContainer.PrintProjectInfo(); 30 | CmdContainer.Run(args); 31 | } 32 | 33 | public static void PrintWelcome() 34 | { 35 | Console.WriteLine($@" 36 | {"ヽ(*^▽^)ノ".Center(60)} 37 | 38 | LinqSharp .NET Command-line Tools {CLI_VERSION}"); 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /dotnet-orm/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "WSL": { 4 | "commandName": "WSL2", 5 | "environmentVariables": {}, 6 | "distributionName": "" 7 | }, 8 | "LinqSharp.Cli": { 9 | "commandName": "Project" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /dotnet-orm/dotnet-orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dotnet-orm 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /push.cmd: -------------------------------------------------------------------------------- 1 | nuget push "LinqSharp/bin/Release/LinqSharp.8.0.20.nupkg" -source nuget.org 2 | nuget push "LinqSharp.EFCore/LinqSharp.EFCore - EF6.0/bin/Release/LinqSharp.EFCore.6.0.8020.nupkg" -source nuget.org 3 | nuget push "LinqSharp.EFCore/LinqSharp.EFCore - EF7.0/bin/Release/LinqSharp.EFCore.7.0.8020.nupkg" -source nuget.org 4 | nuget push "LinqSharp.EFCore/LinqSharp.EFCore - EF8.0/bin/Release/LinqSharp.EFCore.8.0.20.nupkg" -source nuget.org 5 | 6 | nuget push "dotnet-orm/bin/Release/dotnet-orm.0.80.20.nupkg" -source nuget.org 7 | 8 | nuget push "LinqSharp.EFCore/LinqSharp.EFCore.Core/bin/Release/LinqSharp.EFCore.Core.0.8.20.nupkg" -source nuget.org 9 | nuget push "LinqSharp.EFCore/LinqSharp.EFCore.Abstractions/bin/Release/LinqSharp.EFCore.Abstractions.0.1.0.nupkg" -source nuget.org 10 | 11 | rem nuget push "LinqSharp.EFCore.MySql/LinqSharp.EFCore.MySql/bin/Release/LinqSharp.EFCore.MySql.7.0.6.nupkg" -source nuget.org 12 | rem nuget push "LinqSharp.EFCore.MySql/LinqSharp.EFCore.MySql.Compatible/bin/Release/LinqSharp.EFCore.MySql.Compatible.3.1.4.nupkg" -source nuget.org 13 | rem nuget push "LinqSharp.EFCore.SqlServer/LinqSharp.EFCore.SqlServer/bin/Release/LinqSharp.EFCore.SqlServer.7.0.6.nupkg" -source nuget.org 14 | rem nuget push "LinqSharp.EFCore.SqlServer/LinqSharp.EFCore.SqlServer.Compatible/bin/Release/LinqSharp.EFCore.SqlServer.Compatible.2.1.4.nupkg" -source nuget.org 15 | pause 16 | --------------------------------------------------------------------------------