diff --git a/src/EFCore.Cosmos/Metadata/Conventions/StoreKeyConvention.cs b/src/EFCore.Cosmos/Metadata/Conventions/StoreKeyConvention.cs index 1558c0898b3..b86993f7c79 100644 --- a/src/EFCore.Cosmos/Metadata/Conventions/StoreKeyConvention.cs +++ b/src/EFCore.Cosmos/Metadata/Conventions/StoreKeyConvention.cs @@ -5,6 +5,7 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal; using Microsoft.EntityFrameworkCore.Cosmos.ValueGeneration.Internal; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; @@ -28,10 +29,23 @@ public class StoreKeyConvention : IEntityTypeAnnotationChangedConvention, IEntityTypeBaseTypeChangedConvention { -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] public static readonly string IdPropertyName = "id"; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] public static readonly string JObjectPropertyName = "__jObject"; -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Creates a new instance of . diff --git a/src/EFCore.Relational/EFCore.Relational.csproj b/src/EFCore.Relational/EFCore.Relational.csproj index 5f405366bd5..a58bc5f960e 100644 --- a/src/EFCore.Relational/EFCore.Relational.csproj +++ b/src/EFCore.Relational/EFCore.Relational.csproj @@ -7,7 +7,6 @@ Microsoft.EntityFrameworkCore.Relational Microsoft.EntityFrameworkCore true - $(NoWarn);1591 ..\..\EFCore.ruleset diff --git a/src/EFCore.Relational/Extensions/RelationalDbFunctionsExtensions.cs b/src/EFCore.Relational/Extensions/RelationalDbFunctionsExtensions.cs index 96ce783741d..fd186883dae 100644 --- a/src/EFCore.Relational/Extensions/RelationalDbFunctionsExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalDbFunctionsExtensions.cs @@ -9,6 +9,10 @@ // ReSharper disable once CheckNamespace namespace Microsoft.EntityFrameworkCore { + /// + /// Provides CLR methods that get translated to database functions when used in LINQ to Entities queries. + /// The methods on this class are accessed via . + /// public static class RelationalDbFunctionsExtensions { /// diff --git a/src/EFCore.Relational/Infrastructure/RelationalPropertyExtensions.cs b/src/EFCore.Relational/Infrastructure/RelationalPropertyExtensions.cs index 5e9e60ce7c6..173ce32bb08 100644 --- a/src/EFCore.Relational/Infrastructure/RelationalPropertyExtensions.cs +++ b/src/EFCore.Relational/Infrastructure/RelationalPropertyExtensions.cs @@ -8,6 +8,9 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure { + /// + /// Relational extension methods for . + /// public static class RelationalPropertyExtensions { /// diff --git a/src/EFCore.Relational/Metadata/Conventions/RelationalQueryFilterDefiningQueryRewritingConvention.cs b/src/EFCore.Relational/Metadata/Conventions/RelationalQueryFilterDefiningQueryRewritingConvention.cs index 3e7dd8ef3cf..9a0fdcc5e10 100644 --- a/src/EFCore.Relational/Metadata/Conventions/RelationalQueryFilterDefiningQueryRewritingConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/RelationalQueryFilterDefiningQueryRewritingConvention.cs @@ -11,6 +11,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions { + /// public class RelationalQueryFilterDefiningQueryRewritingConvention : QueryFilterDefiningQueryRewritingConvention { /// @@ -26,13 +27,19 @@ public RelationalQueryFilterDefiningQueryRewritingConvention( DbSetAccessRewriter = new RelationalDbSetAccessRewritingExpressionVisitor(Dependencies.ContextType); } + /// protected class RelationalDbSetAccessRewritingExpressionVisitor : DbSetAccessRewritingExpressionVisitor { + /// + /// Creates a new instance of . + /// + /// The clr type of derived DbContext. public RelationalDbSetAccessRewritingExpressionVisitor(Type contextType) : base(contextType) { } + /// protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { Check.NotNull(methodCallExpression, nameof(methodCallExpression)); diff --git a/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs b/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs index 97702cd32e4..24d5a160ed3 100644 --- a/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs @@ -20,6 +20,8 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions /// public class TableSharingConcurrencyTokenConvention : IModelFinalizingConvention { + private const string ConcurrencyPropertyPrefix = "_TableSharingConcurrencyTokenConvention_"; + /// /// Creates a new instance of . /// @@ -37,8 +39,6 @@ public TableSharingConcurrencyTokenConvention( /// protected virtual ProviderConventionSetBuilderDependencies Dependencies { get; } - public static readonly string ConcurrencyPropertyPrefix = "_TableSharingConcurrencyTokenConvention_"; - /// public virtual void ProcessModelFinalizing( IConventionModelBuilder modelBuilder, diff --git a/src/EFCore.Relational/Metadata/Conventions/QueryableDbFunctionConvention.cs b/src/EFCore.Relational/Metadata/Conventions/TableValuedDbFunctionConvention.cs similarity index 100% rename from src/EFCore.Relational/Metadata/Conventions/QueryableDbFunctionConvention.cs rename to src/EFCore.Relational/Metadata/Conventions/TableValuedDbFunctionConvention.cs diff --git a/src/EFCore.Relational/Query/EntityProjectionExpression.cs b/src/EFCore.Relational/Query/EntityProjectionExpression.cs index 123b433cc2a..cf957cd0a0d 100644 --- a/src/EFCore.Relational/Query/EntityProjectionExpression.cs +++ b/src/EFCore.Relational/Query/EntityProjectionExpression.cs @@ -12,6 +12,15 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// An expression that represents an entity in the projection of . + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public class EntityProjectionExpression : Expression { private readonly IDictionary _propertyExpressionsCache @@ -23,6 +32,12 @@ private readonly IDictionary _navigationExp private readonly TableExpressionBase _innerTable; private readonly bool _nullable; + /// + /// Creates a new instance of the class. + /// + /// The entity type to shape. + /// The table from which entity columns are being projected out. + /// A bool value indicating whether this entity instance can be null. public EntityProjectionExpression([NotNull] IEntityType entityType, [NotNull] TableExpressionBase innerTable, bool nullable) { Check.NotNull(entityType, nameof(entityType)); @@ -33,6 +48,11 @@ public EntityProjectionExpression([NotNull] IEntityType entityType, [NotNull] Ta _nullable = nullable; } + /// + /// Creates a new instance of the class. + /// + /// The entity type to shape. + /// A dictionary of column expressions corresponding to properties of the entity type. public EntityProjectionExpression([NotNull] IEntityType entityType, [NotNull] IDictionary propertyExpressions) { Check.NotNull(entityType, nameof(entityType)); @@ -42,10 +62,16 @@ public EntityProjectionExpression([NotNull] IEntityType entityType, [NotNull] ID _propertyExpressionsCache = propertyExpressions; } + /// + /// The entity type being projected out. + /// public virtual IEntityType EntityType { get; } + /// public sealed override ExpressionType NodeType => ExpressionType.Extension; + /// public override Type Type => EntityType.ClrType; + /// protected override Expression VisitChildren(ExpressionVisitor visitor) { Check.NotNull(visitor, nameof(visitor)); @@ -74,6 +100,10 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) : this; } + /// + /// Makes entity instance in projection nullable. + /// + /// A new entity projection expression which can project nullable entity. public virtual EntityProjectionExpression MakeNullable() { if (_innerTable != null) @@ -90,6 +120,11 @@ public virtual EntityProjectionExpression MakeNullable() return new EntityProjectionExpression(EntityType, newCache); } + /// + /// Updates the entity type being projected out to one of the derived type. + /// + /// A derived entity type which should be projected. + /// A new entity projection expression which has the derived type being projected. public virtual EntityProjectionExpression UpdateEntityType([NotNull] IEntityType derivedType) { Check.NotNull(derivedType, nameof(derivedType)); @@ -113,6 +148,11 @@ public virtual EntityProjectionExpression UpdateEntityType([NotNull] IEntityType return new EntityProjectionExpression(derivedType, propertyExpressionCache); } + /// + /// Binds a property with this entity projection to get the SQL representation. + /// + /// A property to bind. + /// A column which is a SQL representation of the property. public virtual ColumnExpression BindProperty([NotNull] IProperty property) { Check.NotNull(property, nameof(property)); @@ -137,6 +177,11 @@ public virtual ColumnExpression BindProperty([NotNull] IProperty property) return expression; } + /// + /// Adds a navigation binding for this entity projection when the target entity type of the navigation is owned or weak. + /// + /// A navigation to add binding for. + /// An entity shaper expression for the target type. public virtual void AddNavigationBinding([NotNull] INavigation navigation, [NotNull] EntityShaperExpression entityShaper) { Check.NotNull(navigation, nameof(navigation)); @@ -156,6 +201,12 @@ public virtual void AddNavigationBinding([NotNull] INavigation navigation, [NotN _navigationExpressionsCache[navigation] = entityShaper; } + /// + /// Binds a navigation with this entity projection to get entity shaper for the target entity type of the navigation which was + /// previously added using method. + /// + /// A navigation to bind. + /// An entity shaper expression for the target entity type of the navigation. public virtual EntityShaperExpression BindNavigation([NotNull] INavigation navigation) { Check.NotNull(navigation, nameof(navigation)); diff --git a/src/EFCore.Relational/Query/ExpressionExtensions.cs b/src/EFCore.Relational/Query/ExpressionExtensions.cs index 3db3e085ae8..fce79c7cbb7 100644 --- a/src/EFCore.Relational/Query/ExpressionExtensions.cs +++ b/src/EFCore.Relational/Query/ExpressionExtensions.cs @@ -9,13 +9,32 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// Extension methods for types. + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public static class ExpressionExtensions { + /// + /// Checks if the given sql unary expression represents a logical NOT operation. + /// + /// A sql unary expression to check. + /// A bool value indicating if the given expression represents a logical NOT operation. public static bool IsLogicalNot([NotNull] this SqlUnaryExpression sqlUnaryExpression) => sqlUnaryExpression.OperatorType == ExpressionType.Not && (sqlUnaryExpression.Type == typeof(bool) || sqlUnaryExpression.Type == typeof(bool?)); + /// + /// Infers type mapping from given s. + /// + /// Expressions to search for to find the type mapping. + /// A relational type mapping inferred from the expressions. public static RelationalTypeMapping InferTypeMapping([NotNull] params SqlExpression[] expressions) { Check.NotNull(expressions, nameof(expressions)); diff --git a/src/EFCore.Relational/Query/IMemberTranslator.cs b/src/EFCore.Relational/Query/IMemberTranslator.cs index 8084bb1f43c..99e789e42ab 100644 --- a/src/EFCore.Relational/Query/IMemberTranslator.cs +++ b/src/EFCore.Relational/Query/IMemberTranslator.cs @@ -2,14 +2,31 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq.Expressions; using System.Reflection; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// A SQL translator for LINQ expression. + /// + /// + /// This interface is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public interface IMemberTranslator { + /// + /// Translates a LINQ to a SQL equivalent. + /// + /// A SQL representation of . + /// The member info from . + /// The return type from . + /// A SQL translation of the . SqlExpression Translate([CanBeNull] SqlExpression instance, [NotNull] MemberInfo member, [NotNull] Type returnType); } } diff --git a/src/EFCore.Relational/Query/IMemberTranslatorPlugin.cs b/src/EFCore.Relational/Query/IMemberTranslatorPlugin.cs index 7bbc3bc17d3..1c966fa8bb1 100644 --- a/src/EFCore.Relational/Query/IMemberTranslatorPlugin.cs +++ b/src/EFCore.Relational/Query/IMemberTranslatorPlugin.cs @@ -8,7 +8,7 @@ namespace Microsoft.EntityFrameworkCore.Query { /// /// - /// Represents plugin member translators. + /// Represents plugin for . /// /// /// The service lifetime is and multiple registrations diff --git a/src/EFCore.Relational/Query/IMemberTranslatorProvider.cs b/src/EFCore.Relational/Query/IMemberTranslatorProvider.cs index 3710dcd70a4..75392671592 100644 --- a/src/EFCore.Relational/Query/IMemberTranslatorProvider.cs +++ b/src/EFCore.Relational/Query/IMemberTranslatorProvider.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq.Expressions; using System.Reflection; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; @@ -11,7 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Query { /// /// - /// Provides translations for object members to instances. + /// Provides translations for LINQ expressions. /// /// /// The service lifetime is . This means a single instance @@ -21,6 +22,13 @@ namespace Microsoft.EntityFrameworkCore.Query /// public interface IMemberTranslatorProvider { + /// + /// Translates a LINQ to a SQL equivalent. + /// + /// A SQL representation of . + /// The member info from . + /// The return type from . + /// A SQL translation of the . SqlExpression Translate([CanBeNull] SqlExpression instance, [NotNull] MemberInfo member, [NotNull] Type returnType); } } diff --git a/src/EFCore.Relational/Query/IMethodCallTranslator.cs b/src/EFCore.Relational/Query/IMethodCallTranslator.cs index 91133be5384..5eefb20d922 100644 --- a/src/EFCore.Relational/Query/IMethodCallTranslator.cs +++ b/src/EFCore.Relational/Query/IMethodCallTranslator.cs @@ -2,14 +2,31 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using System.Linq.Expressions; using System.Reflection; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// A SQL translator for LINQ expression. + /// + /// + /// This interface is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public interface IMethodCallTranslator { + /// + /// Translates a LINQ to a SQL equivalent. + /// + /// A SQL representation of . + /// The method info from . + /// SQL representations of . + /// A SQL translation of the . SqlExpression Translate( [CanBeNull] SqlExpression instance, [NotNull] MethodInfo method, [NotNull] IReadOnlyList arguments); } diff --git a/src/EFCore.Relational/Query/IMethodCallTranslatorPlugin.cs b/src/EFCore.Relational/Query/IMethodCallTranslatorPlugin.cs index 9d9303e1c28..2fa68c47519 100644 --- a/src/EFCore.Relational/Query/IMethodCallTranslatorPlugin.cs +++ b/src/EFCore.Relational/Query/IMethodCallTranslatorPlugin.cs @@ -8,7 +8,7 @@ namespace Microsoft.EntityFrameworkCore.Query { /// /// - /// Represents plugin method call translators. + /// Represents plugin for . /// /// /// The service lifetime is and multiple registrations diff --git a/src/EFCore.Relational/Query/IMethodCallTranslatorProvider.cs b/src/EFCore.Relational/Query/IMethodCallTranslatorProvider.cs index 1ca9be8da40..cb44690811a 100644 --- a/src/EFCore.Relational/Query/IMethodCallTranslatorProvider.cs +++ b/src/EFCore.Relational/Query/IMethodCallTranslatorProvider.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using System.Linq.Expressions; using System.Reflection; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata; @@ -12,7 +13,7 @@ namespace Microsoft.EntityFrameworkCore.Query { /// /// - /// Provides translations for method calls to instances. + /// Provides translations for LINQ expressions. /// /// /// The service lifetime is . This means a single instance @@ -22,6 +23,14 @@ namespace Microsoft.EntityFrameworkCore.Query /// public interface IMethodCallTranslatorProvider { + /// + /// Translates a LINQ to a SQL equivalent. + /// + /// A model to use for translation. + /// A SQL representation of . + /// The method info from . + /// SQL representations of . + /// A SQL translation of the . SqlExpression Translate( [NotNull] IModel model, [CanBeNull] SqlExpression instance, diff --git a/src/EFCore.Relational/Query/IQuerySqlGeneratorFactory.cs b/src/EFCore.Relational/Query/IQuerySqlGeneratorFactory.cs index c700103b337..79f5d1a62b9 100644 --- a/src/EFCore.Relational/Query/IQuerySqlGeneratorFactory.cs +++ b/src/EFCore.Relational/Query/IQuerySqlGeneratorFactory.cs @@ -17,6 +17,10 @@ namespace Microsoft.EntityFrameworkCore.Query /// public interface IQuerySqlGeneratorFactory { + /// + /// Creates a new . + /// + /// A SQL generator. QuerySqlGenerator Create(); } } diff --git a/src/EFCore.Relational/Query/IRelationalParameterBasedQueryTranslationPostprocessorFactory.cs b/src/EFCore.Relational/Query/IRelationalParameterBasedQueryTranslationPostprocessorFactory.cs index a2456edd2cb..5f2803ab642 100644 --- a/src/EFCore.Relational/Query/IRelationalParameterBasedQueryTranslationPostprocessorFactory.cs +++ b/src/EFCore.Relational/Query/IRelationalParameterBasedQueryTranslationPostprocessorFactory.cs @@ -17,6 +17,11 @@ namespace Microsoft.EntityFrameworkCore.Query /// public interface IRelationalParameterBasedQueryTranslationPostprocessorFactory { + /// + /// Creates a new . + /// + /// A bool value indicating if relational nulls should be used. + /// A relational parameter based query translation postprocessor. RelationalParameterBasedQueryTranslationPostprocessor Create(bool useRelationalNulls); } } diff --git a/src/EFCore.Relational/Query/IRelationalSqlTranslatingExpressionVisitorFactory.cs b/src/EFCore.Relational/Query/IRelationalSqlTranslatingExpressionVisitorFactory.cs index 16a1c90d119..b8a62d8554a 100644 --- a/src/EFCore.Relational/Query/IRelationalSqlTranslatingExpressionVisitorFactory.cs +++ b/src/EFCore.Relational/Query/IRelationalSqlTranslatingExpressionVisitorFactory.cs @@ -18,6 +18,12 @@ namespace Microsoft.EntityFrameworkCore.Query /// public interface IRelationalSqlTranslatingExpressionVisitorFactory { + /// + /// Creates a new . + /// + /// The query compilation context to use. + /// The visitor to use to translate subqueries. + /// A relational sql translating expression visitor. RelationalSqlTranslatingExpressionVisitor Create( [NotNull] QueryCompilationContext queryCompilationContext, [NotNull] QueryableMethodTranslatingExpressionVisitor queryableMethodTranslatingExpressionVisitor); diff --git a/src/EFCore.Relational/Query/ISqlExpressionFactory.cs b/src/EFCore.Relational/Query/ISqlExpressionFactory.cs index ea80efa5452..33a7dab63ac 100644 --- a/src/EFCore.Relational/Query/ISqlExpressionFactory.cs +++ b/src/EFCore.Relational/Query/ISqlExpressionFactory.cs @@ -24,19 +24,56 @@ namespace Microsoft.EntityFrameworkCore.Query /// public interface ISqlExpressionFactory { + /// + /// Gets the relational database type for a given object, throwing if no mapping is found. + /// + /// The object to get the mapping for. + /// The type mapping to be used. [Obsolete("Use IRelationalTypeMappingSource directly.")] RelationalTypeMapping GetTypeMappingForValue([CanBeNull] object value); + /// + /// Finds the type mapping for a given . + /// + /// The CLR type. + /// The type mapping, or null if none was found. [Obsolete("Use IRelationalTypeMappingSource directly.")] RelationalTypeMapping FindMapping([NotNull] Type type); + /// + /// Applies type mapping to the given . + /// + /// A SQL expression to apply type mapping. + /// A type mapping to apply. + /// A SQL expression with given type mapping applied. SqlExpression ApplyTypeMapping([CanBeNull] SqlExpression sqlExpression, [CanBeNull] RelationalTypeMapping typeMapping); + /// + /// Applies default type mapping to given . + /// + /// A SQL Expression to apply default type mapping. + /// A SQL expression with default type mapping applied. SqlExpression ApplyDefaultTypeMapping([CanBeNull] SqlExpression sqlExpression); + /// + /// Creates a new with the given arguments. + /// + /// An reprenting SQL unary operator. + /// A to apply unary operator on. + /// The type of the created expression. + /// A type mapping to be assigned to the created expression. + /// A with the given arguments. SqlUnaryExpression MakeUnary( ExpressionType operatorType, [NotNull] SqlExpression operand, [NotNull] Type type, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new with the given arguments. + /// + /// An reprenting SQL unary operator. + /// The left operand of binary operation. + /// The right operand of binary operation. + /// A type mapping to be assigned to the created expression. + /// A with the given arguments. SqlBinaryExpression MakeBinary( ExpressionType operatorType, [NotNull] SqlExpression left, @@ -44,62 +81,215 @@ SqlBinaryExpression MakeBinary( [CanBeNull] RelationalTypeMapping typeMapping); // Comparison + /// + /// Creates a which represents an equality comparison. + /// + /// The left operand. + /// The right operand. + /// An expression representing a SQL equality comparison. SqlBinaryExpression Equal([NotNull] SqlExpression left, [NotNull] SqlExpression right); + /// + /// Creates a which represents an inequality comparison. + /// + /// The left operand. + /// The right operand. + /// An expression representing a SQL inequality comparison. SqlBinaryExpression NotEqual([NotNull] SqlExpression left, [NotNull] SqlExpression right); + /// + /// Creates a which represents a greater than comparison. + /// + /// The left operand. + /// The right operand. + /// An expression representing a SQL greater than comparison. SqlBinaryExpression GreaterThan([NotNull] SqlExpression left, [NotNull] SqlExpression right); + /// + /// Creates a which represents a greater than or equal comparison. + /// + /// The left operand. + /// The right operand. + /// An expression representing a SQL greater than or equal comparison. SqlBinaryExpression GreaterThanOrEqual([NotNull] SqlExpression left, [NotNull] SqlExpression right); + /// + /// Creates a which represents a less than comparison. + /// + /// The left operand. + /// The right operand. + /// An expression representing a SQL less than comparison. SqlBinaryExpression LessThan([NotNull] SqlExpression left, [NotNull] SqlExpression right); + /// + /// Creates a which represents a less than or equal comparison. + /// + /// The left operand. + /// The right operand. + /// An expression representing a SQL less than or equal comparison. SqlBinaryExpression LessThanOrEqual([NotNull] SqlExpression left, [NotNull] SqlExpression right); // Logical + /// + /// Creates a which represents a logical AND operation. + /// + /// The left operand. + /// The right operand. + /// An expression representing a SQL AND operation. SqlBinaryExpression AndAlso([NotNull] SqlExpression left, [NotNull] SqlExpression right); + /// + /// Creates a which represents a logical OR operation. + /// + /// The left operand. + /// The right operand. + /// An expression representing a SQL OR operation. SqlBinaryExpression OrElse([NotNull] SqlExpression left, [NotNull] SqlExpression right); // Arithmetic + /// + /// Creates a which represents an addition. + /// + /// The left operand. + /// The right operand. + /// A type mapping to be assigned to the created expression. + /// An expression representing a SQL addition. SqlBinaryExpression Add( [NotNull] SqlExpression left, [NotNull] SqlExpression right, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a which represents a subtraction. + /// + /// The left operand. + /// The right operand. + /// A type mapping to be assigned to the created expression. + /// An expression representing a SQL subtraction. SqlBinaryExpression Subtract( [NotNull] SqlExpression left, [NotNull] SqlExpression right, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a which represents a multiplication. + /// + /// The left operand. + /// The right operand. + /// A type mapping to be assigned to the created expression. + /// An expression representing a SQL multiplication. SqlBinaryExpression Multiply( [NotNull] SqlExpression left, [NotNull] SqlExpression right, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a which represents a division. + /// + /// The left operand. + /// The right operand. + /// A type mapping to be assigned to the created expression. + /// An expression representing a SQL division. SqlBinaryExpression Divide( [NotNull] SqlExpression left, [NotNull] SqlExpression right, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a which represents a modulo operation. + /// + /// The left operand. + /// The right operand. + /// A type mapping to be assigned to the created expression. + /// An expression representing a SQL modulo operation. SqlBinaryExpression Modulo( [NotNull] SqlExpression left, [NotNull] SqlExpression right, [CanBeNull] RelationalTypeMapping typeMapping = null); // Bitwise + /// + /// Creates a which represents a bitwise AND operation. + /// + /// The left operand. + /// The right operand. + /// A type mapping to be assigned to the created expression. + /// An expression representing a SQL bitwise AND operation. SqlBinaryExpression And( [NotNull] SqlExpression left, [NotNull] SqlExpression right, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a which represents a bitwise OR operation. + /// + /// The left operand. + /// The right operand. + /// A type mapping to be assigned to the created expression. + /// An expression representing a SQL bitwise OR operation. SqlBinaryExpression Or( [NotNull] SqlExpression left, [NotNull] SqlExpression right, [CanBeNull] RelationalTypeMapping typeMapping = null); // Other + /// + /// Creates a which represents a bitwise OR operation. + /// + /// The left operand. + /// The right operand. + /// A type mapping to be assigned to the created expression. + /// An expression representing a SQL bitwise OR operation. SqlFunctionExpression Coalesce( [NotNull] SqlExpression left, [NotNull] SqlExpression right, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represent equality to null. + /// + /// A to compare to null. + /// An expression representing IS NULL construct in a SQL tree. SqlUnaryExpression IsNull([NotNull] SqlExpression operand); + + /// + /// Creates a new which represent inequality to null. + /// + /// A to compare to non null. + /// An expression representing IS NOT NULL construct in a SQL tree. SqlUnaryExpression IsNotNull([NotNull] SqlExpression operand); + /// + /// Creates a new which represent casting a SQL expression to different type. + /// + /// A to cast. + /// The return type of the expression after cast. + /// A relational type mapping to use for conversion. + /// An expression representing cast operation in a SQL tree. SqlUnaryExpression Convert( [NotNull] SqlExpression operand, [NotNull] Type type, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represent a NOT operation in a SQL tree. + /// + /// A to apply NOT on. + /// An expression representing a NOT operation in a SQL tree. SqlUnaryExpression Not([NotNull] SqlExpression operand); + + /// + /// Creates a new which represent a negation operation in a SQL tree. + /// + /// A to apply NOT on. + /// An expression representing a negation operation in a SQL tree. SqlUnaryExpression Negate([NotNull] SqlExpression operand); + /// + /// Creates a new which represent a CASE statement in a SQL tree. + /// + /// An expression to compare with in . + /// A list of to compare and get result from. + /// An expression representing a CASE statement in a SQL tree. CaseExpression Case([NotNull] SqlExpression operand, [NotNull] params CaseWhenClause[] whenClauses); + /// + /// Creates a new which represent a CASE statement in a SQL tree. + /// + /// A list of to evaluate condition and get result from. + /// A value to return if no matches, if any. + /// An expression representing a CASE statement in a SQL tree. CaseExpression Case([NotNull] IReadOnlyList whenClauses, [CanBeNull] SqlExpression elseResult); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// The name of the function. + /// The arguments of the function. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. [Obsolete("Use overload that explicitly specifies value for 'argumentsPropagateNullability' argument.")] SqlFunctionExpression Function( [NotNull] string name, @@ -107,6 +297,15 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// The schema in which the function is defined. + /// The name of the function. + /// The arguments of the function. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. [Obsolete("Use overload that explicitly specifies value for 'argumentsPropagateNullability' argument.")] SqlFunctionExpression Function( [CanBeNull] string schema, @@ -115,6 +314,15 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// An expression on which the function is applied. + /// The name of the function. + /// The arguments of the function. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. [Obsolete("Use overload that explicitly specifies value for 'instancePropagatesNullability' and 'argumentsPropagateNullability' arguments.")] SqlFunctionExpression Function( [NotNull] SqlExpression instance, @@ -123,12 +331,27 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// The name of the function. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. [Obsolete("Use overload that explicitly specifies value for 'nullable' argument.")] SqlFunctionExpression Function( [NotNull] string name, [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// The schema in which the function is defined. + /// The name of the function. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. [Obsolete("Use overload that explicitly specifies value for 'nullable' argument.")] SqlFunctionExpression Function( [NotNull] string schema, @@ -136,6 +359,14 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// An expression on which the function is applied. + /// The name of the function. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. [Obsolete("Use overload that explicitly specifies value for 'instancePropagatesNullability' argument.")] SqlFunctionExpression Function( [NotNull] SqlExpression instance, @@ -143,6 +374,16 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// The name of the function. + /// The arguments of the function. + /// A bool value indicating whether this function can return null. + /// A list of bool values indicating whether individual arguments propagate null to result. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. SqlFunctionExpression Function( [NotNull] string name, [NotNull] IEnumerable arguments, @@ -151,6 +392,17 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// The schema in which the function is defined. + /// The name of the function. + /// The arguments of the function. + /// A bool value indicating whether this function can return null. + /// A list of bool values indicating whether individual arguments propagate null to result. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. SqlFunctionExpression Function( [NotNull] string schema, [NotNull] string name, @@ -160,6 +412,18 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// An expression on which the function is applied. + /// The name of the function. + /// The arguments of the function. + /// A bool value indicating whether this function can return null. + /// A value indicating if instance propagates null to result. + /// A list of bool values indicating whether individual arguments propagate null to result. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. SqlFunctionExpression Function( [NotNull] SqlExpression instance, [NotNull] string name, @@ -170,12 +434,29 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// The name of the function. + /// A bool value indicating whether this function can return null. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. SqlFunctionExpression Function( [NotNull] string name, bool nullable, [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// The schema in which the function is defined. + /// The name of the function. + /// A bool value indicating whether this function can return null. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. SqlFunctionExpression Function( [NotNull] string schema, [NotNull] string name, @@ -183,6 +464,16 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents a function call in a SQL tree. + /// + /// An expression on which the function is applied. + /// The name of the function. + /// A bool value indicating whether this function can return null. + /// A value indicating if instance propagates null to result. + /// The of the expression. + /// The associated with the expression. + /// An expression representing a function call in a SQL tree. SqlFunctionExpression Function( [NotNull] SqlExpression instance, [NotNull] string name, @@ -191,16 +482,89 @@ SqlFunctionExpression Function( [NotNull] Type returnType, [CanBeNull] RelationalTypeMapping typeMapping = null); + /// + /// Creates a new which represents an EXISTS operation in a SQL tree. + /// + /// A subquery to check existence of. + /// A value indicating if the existence check is negated. + /// An expression representing an EXISTS operation in a SQL tree. ExistsExpression Exists([NotNull] SelectExpression subquery, bool negated); + + /// + /// Creates a new which represents an IN operation in a SQL tree. + /// + /// An item to look into values. + /// A list of values in which item is searched. + /// A value indicating if the item should be present in the values or absent. + /// An expression representing an IN operation in a SQL tree. InExpression In([NotNull] SqlExpression item, [NotNull] SqlExpression values, bool negated); + + /// + /// Creates a new which represents an IN operation in a SQL tree. + /// + /// An item to look into values. + /// A subquery in which item is searched. + /// A value indicating if the item should be present in the values or absent. + /// An expression representing an IN operation in a SQL tree. InExpression In([NotNull] SqlExpression item, [NotNull] SelectExpression subquery, bool negated); + + /// + /// Creates a new which represents a LIKE in a SQL tree. + /// + /// An expression on which LIKE is applied. + /// A pattern to search. + /// An optional escape character to use in LIKE. + /// An expression representing a LIKE in a SQL tree. LikeExpression Like([NotNull] SqlExpression match, [NotNull] SqlExpression pattern, [CanBeNull] SqlExpression escapeChar = null); + + /// + /// Creates a new which represents a constant in a SQL tree. + /// + /// A value. + /// The associated with the expression. + /// An expression representing a LIKE in a SQL tree. SqlConstantExpression Constant([NotNull] object value, [CanBeNull] RelationalTypeMapping typeMapping = null); + + /// + /// Creates a new which represents a SQL token. + /// + /// A string token to print in SQL tree. + /// An expression representing a SQL token. SqlFragmentExpression Fragment([NotNull] string sql); + /// + /// Creates a new which represents a SELECT in a SQL tree projecting a + /// or 1 from no table and without any composition. + /// + /// A to project. + /// An expression representing a SELECT in a SQL tree. SelectExpression Select([CanBeNull] SqlExpression projection); + + /// + /// Creates a new which represents a SELECT in a SQL tree projecting an entity type from + /// a table source created using default mapping in the model. + /// + /// An entity type to project. + /// An expression representing a SELECT in a SQL tree. SelectExpression Select([NotNull] IEntityType entityType); + + /// + /// Creates a new which represents a SELECT in a SQL tree projecting an entity type from + /// a table source. + /// + /// An entity type to project. + /// A table source to project from. + /// An expression representing a SELECT in a SQL tree. SelectExpression Select([NotNull] IEntityType entityType, [NotNull] TableExpressionBase tableExpressionBase); + + /// + /// Creates a new which represents a SELECT in a SQL tree projecting an entity type from + /// a table source created using a custom SQL. + /// + /// An entity type to project. + /// A custom SQL for the table source. + /// An expression representing parameters passed to the custom SQL. + /// An expression representing a SELECT in a SQL tree. SelectExpression Select([NotNull] IEntityType entityType, [NotNull] string sql, [NotNull] Expression sqlArguments); } } diff --git a/src/EFCore.Relational/Query/NullabilityBasedSqlProcessingExpressionVisitor.cs b/src/EFCore.Relational/Query/NullabilityBasedSqlProcessingExpressionVisitor.cs index f518f0d54df..fc53d7d39ca 100644 --- a/src/EFCore.Relational/Query/NullabilityBasedSqlProcessingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/NullabilityBasedSqlProcessingExpressionVisitor.cs @@ -8,7 +8,6 @@ using System.Linq.Expressions; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; diff --git a/src/EFCore.Relational/Query/QuerySqlGenerator.cs b/src/EFCore.Relational/Query/QuerySqlGenerator.cs index c1121f58718..f886cf5aebd 100644 --- a/src/EFCore.Relational/Query/QuerySqlGenerator.cs +++ b/src/EFCore.Relational/Query/QuerySqlGenerator.cs @@ -15,6 +15,15 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// A query SQL generator to get for given . + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public class QuerySqlGenerator : SqlExpressionVisitor { private static readonly Regex _composableSql @@ -43,6 +52,10 @@ private static readonly Regex _composableSql { ExpressionType.Or, " | " } }; + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. public QuerySqlGenerator([NotNull] QuerySqlGeneratorDependencies dependencies) { Check.NotNull(dependencies, nameof(dependencies)); @@ -53,8 +66,16 @@ public QuerySqlGenerator([NotNull] QuerySqlGeneratorDependencies dependencies) _sqlGenerationHelper = dependencies.SqlGenerationHelper; } + /// + /// Parameter object containing service dependencies. + /// protected virtual QuerySqlGeneratorDependencies Dependencies { get; } + /// + /// Gets a relational command for a . + /// + /// A select expression to print in command text. + /// A relational command with a SQL represented by the select expression. public virtual IRelationalCommand GetCommand([NotNull] SelectExpression selectExpression) { Check.NotNull(selectExpression, nameof(selectExpression)); @@ -80,8 +101,15 @@ public virtual IRelationalCommand GetCommand([NotNull] SelectExpression selectEx /// protected virtual string AliasSeparator { get; } = " AS "; + /// + /// The current SQL command builder. + /// protected virtual IRelationalCommandBuilder Sql => _relationalCommandBuilder; + /// + /// Generates the head comment for tags. + /// + /// A select expression to generate tags for. protected virtual void GenerateTagsHeaderComment([NotNull] SelectExpression selectExpression) { Check.NotNull(selectExpression, nameof(selectExpression)); @@ -97,6 +125,7 @@ protected virtual void GenerateTagsHeaderComment([NotNull] SelectExpression sele } } + /// protected override Expression VisitSqlFragment(SqlFragmentExpression sqlFragmentExpression) { Check.NotNull(sqlFragmentExpression, nameof(sqlFragmentExpression)); @@ -124,6 +153,7 @@ private bool IsNonComposedSetOperation(SelectExpression selectExpression) column.Name, setOperation.Source1.Projection[index].Alias, StringComparison.OrdinalIgnoreCase)) .All(e => e); + /// protected override Expression VisitSelect(SelectExpression selectExpression) { Check.NotNull(selectExpression, nameof(selectExpression)); @@ -209,13 +239,13 @@ protected override Expression VisitSelect(SelectExpression selectExpression) } /// - /// Generates a pseudo FROM clause. Required by some providers - /// when a query has no actual FROM clause. + /// Generates a pseudo FROM clause. Required by some providers when a query has no actual FROM clause. /// protected virtual void GeneratePseudoFromClause() { } + /// protected override Expression VisitProjection(ProjectionExpression projectionExpression) { Check.NotNull(projectionExpression, nameof(projectionExpression)); @@ -232,6 +262,7 @@ protected override Expression VisitProjection(ProjectionExpression projectionExp return projectionExpression; } + /// protected override Expression VisitSqlFunction(SqlFunctionExpression sqlFunctionExpression) { Check.NotNull(sqlFunctionExpression, nameof(sqlFunctionExpression)); @@ -269,6 +300,7 @@ protected override Expression VisitSqlFunction(SqlFunctionExpression sqlFunction return sqlFunctionExpression; } + /// protected override Expression VisitTableValuedFunction(TableValuedFunctionExpression tableValuedFunctionExpression) { Check.NotNull(tableValuedFunctionExpression, nameof(tableValuedFunctionExpression)); @@ -294,6 +326,7 @@ protected override Expression VisitTableValuedFunction(TableValuedFunctionExpres return tableValuedFunctionExpression; } + /// protected override Expression VisitColumn(ColumnExpression columnExpression) { Check.NotNull(columnExpression, nameof(columnExpression)); @@ -306,6 +339,7 @@ protected override Expression VisitColumn(ColumnExpression columnExpression) return columnExpression; } + /// protected override Expression VisitTable(TableExpression tableExpression) { Check.NotNull(tableExpression, nameof(tableExpression)); @@ -372,6 +406,7 @@ private void GenerateFromSql(FromSqlExpression fromSqlExpression) _relationalCommandBuilder.AppendLines(sql); } + /// protected override Expression VisitFromSql(FromSqlExpression fromSqlExpression) { Check.NotNull(fromSqlExpression, nameof(fromSqlExpression)); @@ -395,6 +430,7 @@ protected override Expression VisitFromSql(FromSqlExpression fromSqlExpression) return fromSqlExpression; } + /// protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression) { Check.NotNull(sqlBinaryExpression, nameof(sqlBinaryExpression)); @@ -435,6 +471,7 @@ protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpres private static bool RequiresBrackets(SqlExpression expression) => expression is SqlBinaryExpression || expression is LikeExpression; + /// protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstantExpression) { Check.NotNull(sqlConstantExpression, nameof(sqlConstantExpression)); @@ -445,6 +482,7 @@ protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstant return sqlConstantExpression; } + /// protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression) { Check.NotNull(sqlParameterExpression, nameof(sqlParameterExpression)); @@ -467,6 +505,7 @@ protected override Expression VisitSqlParameter(SqlParameterExpression sqlParame return sqlParameterExpression; } + /// protected override Expression VisitOrdering(OrderingExpression orderingExpression) { Check.NotNull(orderingExpression, nameof(orderingExpression)); @@ -489,6 +528,7 @@ protected override Expression VisitOrdering(OrderingExpression orderingExpressio return orderingExpression; } + /// protected override Expression VisitLike(LikeExpression likeExpression) { Check.NotNull(likeExpression, nameof(likeExpression)); @@ -506,6 +546,7 @@ protected override Expression VisitLike(LikeExpression likeExpression) return likeExpression; } + /// protected override Expression VisitCollate(CollateExpression collateExpresion) { Check.NotNull(collateExpresion, nameof(collateExpresion)); @@ -519,6 +560,7 @@ protected override Expression VisitCollate(CollateExpression collateExpresion) return collateExpresion; } + /// protected override Expression VisitCase(CaseExpression caseExpression) { Check.NotNull(caseExpression, nameof(caseExpression)); @@ -559,6 +601,7 @@ protected override Expression VisitCase(CaseExpression caseExpression) return caseExpression; } + /// protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) { Check.NotNull(sqlUnaryExpression, nameof(sqlUnaryExpression)); @@ -627,6 +670,7 @@ when sqlUnaryExpression.IsLogicalNot(): return sqlUnaryExpression; } + /// protected override Expression VisitExists(ExistsExpression existsExpression) { Check.NotNull(existsExpression, nameof(existsExpression)); @@ -648,6 +692,7 @@ protected override Expression VisitExists(ExistsExpression existsExpression) return existsExpression; } + /// protected override Expression VisitIn(InExpression inExpression) { Check.NotNull(inExpression, nameof(inExpression)); @@ -680,6 +725,11 @@ protected override Expression VisitIn(InExpression inExpression) return inExpression; } + /// + /// Generates a SQL operator for a SQL binary operation. + /// + /// A SQL binary operation. + /// A string representation of the binary operator. protected virtual string GenerateOperator([NotNull] SqlBinaryExpression binaryExpression) { Check.NotNull(binaryExpression, nameof(binaryExpression)); @@ -687,11 +737,19 @@ protected virtual string GenerateOperator([NotNull] SqlBinaryExpression binaryEx return _operatorMap[binaryExpression.OperatorType]; } + /// + /// Generates a TOP construct in the relational command + /// + /// A select expression to use. protected virtual void GenerateTop([NotNull] SelectExpression selectExpression) { Check.NotNull(selectExpression, nameof(selectExpression)); } + /// + /// Generates an ORDER BY clause in the relational command + /// + /// A select expression to use. protected virtual void GenerateOrderings([NotNull] SelectExpression selectExpression) { Check.NotNull(selectExpression, nameof(selectExpression)); @@ -720,6 +778,10 @@ protected virtual void GenerateOrderings([NotNull] SelectExpression selectExpres } } + /// + /// Generates a LIMIT...OFFSET... construct in the relational command + /// + /// A select expression to use. protected virtual void GenerateLimitOffset([NotNull] SelectExpression selectExpression) { Check.NotNull(selectExpression, nameof(selectExpression)); @@ -771,6 +833,7 @@ private void GenerateList( } } + /// protected override Expression VisitCrossJoin(CrossJoinExpression crossJoinExpression) { Check.NotNull(crossJoinExpression, nameof(crossJoinExpression)); @@ -781,6 +844,7 @@ protected override Expression VisitCrossJoin(CrossJoinExpression crossJoinExpres return crossJoinExpression; } + /// protected override Expression VisitCrossApply(CrossApplyExpression crossApplyExpression) { Check.NotNull(crossApplyExpression, nameof(crossApplyExpression)); @@ -791,6 +855,7 @@ protected override Expression VisitCrossApply(CrossApplyExpression crossApplyExp return crossApplyExpression; } + /// protected override Expression VisitOuterApply(OuterApplyExpression outerApplyExpression) { Check.NotNull(outerApplyExpression, nameof(outerApplyExpression)); @@ -801,6 +866,7 @@ protected override Expression VisitOuterApply(OuterApplyExpression outerApplyExp return outerApplyExpression; } + /// protected override Expression VisitInnerJoin(InnerJoinExpression innerJoinExpression) { Check.NotNull(innerJoinExpression, nameof(innerJoinExpression)); @@ -813,6 +879,7 @@ protected override Expression VisitInnerJoin(InnerJoinExpression innerJoinExpres return innerJoinExpression; } + /// protected override Expression VisitLeftJoin(LeftJoinExpression leftJoinExpression) { Check.NotNull(leftJoinExpression, nameof(leftJoinExpression)); @@ -825,6 +892,7 @@ protected override Expression VisitLeftJoin(LeftJoinExpression leftJoinExpressio return leftJoinExpression; } + /// protected override Expression VisitScalarSubquery(ScalarSubqueryExpression scalarSubqueryExpression) { Check.NotNull(scalarSubqueryExpression, nameof(scalarSubqueryExpression)); @@ -840,6 +908,7 @@ protected override Expression VisitScalarSubquery(ScalarSubqueryExpression scala return scalarSubqueryExpression; } + /// protected override Expression VisitRowNumber(RowNumberExpression rowNumberExpression) { Check.NotNull(rowNumberExpression, nameof(rowNumberExpression)); @@ -859,24 +928,33 @@ protected override Expression VisitRowNumber(RowNumberExpression rowNumberExpres return rowNumberExpression; } + /// + /// Generates a set operation in the relational command. + /// + /// A set operation to print. protected virtual void GenerateSetOperation([NotNull] SetOperationBase setOperation) { Check.NotNull(setOperation, nameof(setOperation)); - string getSetOperation() => setOperation switch + GenerateSetOperationOperand(setOperation, setOperation.Source1); + _relationalCommandBuilder.AppendLine(); + _relationalCommandBuilder.AppendLine($"{GetSetOperation(setOperation)}{(setOperation.IsDistinct ? "" : " ALL")}"); + GenerateSetOperationOperand(setOperation, setOperation.Source2); + + static string GetSetOperation(SetOperationBase operation) => operation switch { ExceptExpression _ => "EXCEPT", IntersectExpression _ => "INTERSECT", UnionExpression _ => "UNION", _ => throw new InvalidOperationException(CoreStrings.UnknownEntity("SetOperationType")), }; - - GenerateSetOperationOperand(setOperation, setOperation.Source1); - _relationalCommandBuilder.AppendLine(); - _relationalCommandBuilder.AppendLine($"{getSetOperation()}{(setOperation.IsDistinct ? "" : " ALL")}"); - GenerateSetOperationOperand(setOperation, setOperation.Source2); } + /// + /// Generates an operand for a given set operation in the relational command. + /// + /// A set operation to use. + /// A set operation operand to print. protected virtual void GenerateSetOperationOperand([NotNull] SetOperationBase setOperation, [NotNull] SelectExpression operand) { Check.NotNull(setOperation, nameof(setOperation)); @@ -915,6 +993,7 @@ private void GenerateSetOperationHelper(SetOperationBase setOperation) .Append(_sqlGenerationHelper.DelimitIdentifier(setOperation.Alias)); } + /// protected override Expression VisitExcept(ExceptExpression exceptExpression) { Check.NotNull(exceptExpression, nameof(exceptExpression)); @@ -924,6 +1003,7 @@ protected override Expression VisitExcept(ExceptExpression exceptExpression) return exceptExpression; } + /// protected override Expression VisitIntersect(IntersectExpression intersectExpression) { Check.NotNull(intersectExpression, nameof(intersectExpression)); @@ -933,6 +1013,7 @@ protected override Expression VisitIntersect(IntersectExpression intersectExpres return intersectExpression; } + /// protected override Expression VisitUnion(UnionExpression unionExpression) { Check.NotNull(unionExpression, nameof(unionExpression)); diff --git a/src/EFCore.Relational/Query/RelationalCollectionShaperExpression.cs b/src/EFCore.Relational/Query/RelationalCollectionShaperExpression.cs index 379d758e0bd..42f5537f9cd 100644 --- a/src/EFCore.Relational/Query/RelationalCollectionShaperExpression.cs +++ b/src/EFCore.Relational/Query/RelationalCollectionShaperExpression.cs @@ -11,8 +11,27 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// An expression that represents creation of a collection for relational provider in . + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public class RelationalCollectionShaperExpression : Expression, IPrintableExpression { + /// + /// Creates a new instance of the class. + /// + /// A unique id for the collection being shaped. + /// An identifier for the parent element. + /// An identifier for the outer element. + /// An identifier for the element in the collection. + /// An expression used to create individual elements of the collection. + /// A navigation associated with this collection, if any. + /// The clr type of individual elements in the collection. [Obsolete("Use ctor which takes value comaprers.")] public RelationalCollectionShaperExpression( int collectionId, @@ -28,6 +47,19 @@ public RelationalCollectionShaperExpression( } + /// + /// Creates a new instance of the class. + /// + /// A unique id for the collection being shaped. + /// An identifier for the parent element. + /// An identifier for the outer element. + /// An identifier for the element in the collection. + /// A list of value comparers to compare parent identifier. + /// A list of value comparers to compare outer identifier. + /// A list of value comparers to compare self identifier. + /// An expression used to create individual elements of the collection. + /// A navigation associated with this collection, if any. + /// The clr type of individual elements in the collection. public RelationalCollectionShaperExpression( int collectionId, [NotNull] Expression parentIdentifier, @@ -58,21 +90,54 @@ public RelationalCollectionShaperExpression( ElementType = elementType; } + /// + /// A unique id for this collection shaper. + /// public virtual int CollectionId { get; } + /// + /// The identifier for the parent element. + /// public virtual Expression ParentIdentifier { get; } + /// + /// The identifier for the outer element. + /// public virtual Expression OuterIdentifier { get; } + /// + /// The identifier for the element in the collection. + /// public virtual Expression SelfIdentifier { get; } + /// + /// The list of value comparers to compare parent identifier. + /// public virtual IReadOnlyList ParentIdentifierValueComparers { get; } + /// + /// The list of value comparers to compare outer identifier. + /// public virtual IReadOnlyList OuterIdentifierValueComparers { get; } + /// + /// The list of value comparers to compare self identifier. + /// public virtual IReadOnlyList SelfIdentifierValueComparers { get; } + /// + /// The expression to create inner elements. + /// public virtual Expression InnerShaper { get; } + /// + /// The navigation if associated with the collection. + /// public virtual INavigation Navigation { get; } + /// + /// The clr type of elements of the collection. + /// public virtual Type ElementType { get; } + /// public override Type Type => Navigation?.ClrType ?? typeof(List<>).MakeGenericType(ElementType); + /// public sealed override ExpressionType NodeType => ExpressionType.Extension; + /// protected override Expression VisitChildren(ExpressionVisitor visitor) { Check.NotNull(visitor, nameof(visitor)); @@ -85,6 +150,15 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) return Update(parentIdentifier, outerIdentifier, selfIdentifier, innerShaper); } + /// + /// Creates a new expression that is like this one, but using the supplied children. If all of the children are the same, it will + /// return this expression. + /// + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// This expression if no children changed, or an expression with the updated children. public virtual RelationalCollectionShaperExpression Update( [NotNull] Expression parentIdentifier, [NotNull] Expression outerIdentifier, @@ -107,6 +181,7 @@ public virtual RelationalCollectionShaperExpression Update( : this; } + /// public virtual void Print(ExpressionPrinter expressionPrinter) { Check.NotNull(expressionPrinter, nameof(expressionPrinter)); diff --git a/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs b/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs index 446d31753fb..0bb146eb00b 100644 --- a/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs +++ b/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Linq; using System.Linq.Expressions; using JetBrains.Annotations; @@ -11,14 +12,36 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// An expression that represents creation of an entity instance for a relational provider in . + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public class RelationalEntityShaperExpression : EntityShaperExpression { + /// + /// Creates a new instance of the class. + /// + /// The entity type to shape. + /// An expression of ValueBuffer to get values for properties of the entity. + /// A bool value indicating whether this entity instance can be null. public RelationalEntityShaperExpression([NotNull] IEntityType entityType, [NotNull] Expression valueBufferExpression, bool nullable) : base(entityType, valueBufferExpression, nullable, null) { } - public RelationalEntityShaperExpression( + /// + /// Creates a new instance of the class. + /// + /// The entity type to shape. + /// An expression of ValueBuffer to get values for properties of the entity. + /// Whether this entity instance can be null. + /// An expression of to determine which entity type to materialize. + protected RelationalEntityShaperExpression( [NotNull] IEntityType entityType, [NotNull] Expression valueBufferExpression, bool nullable, @@ -27,6 +50,7 @@ public RelationalEntityShaperExpression( { } + /// protected override LambdaExpression GenerateMaterializationCondition(IEntityType entityType, bool nullable) { Check.NotNull(entityType, nameof(EntityType)); @@ -77,6 +101,7 @@ protected override LambdaExpression GenerateMaterializationCondition(IEntityType return baseCondition; } + /// public override EntityShaperExpression WithEntityType(IEntityType entityType) { Check.NotNull(entityType, nameof(entityType)); @@ -86,12 +111,14 @@ public override EntityShaperExpression WithEntityType(IEntityType entityType) : this; } + /// public override EntityShaperExpression MarkAsNullable() => !IsNullable // Marking nullable requires recomputation of Discriminator condition ? new RelationalEntityShaperExpression(EntityType, ValueBufferExpression, true) : this; + /// public override EntityShaperExpression Update(Expression valueBufferExpression) { Check.NotNull(valueBufferExpression, nameof(valueBufferExpression)); diff --git a/src/EFCore.Relational/Query/RelationalMemberTranslatorProvider.cs b/src/EFCore.Relational/Query/RelationalMemberTranslatorProvider.cs index e63d09447e8..9a72933ffd1 100644 --- a/src/EFCore.Relational/Query/RelationalMemberTranslatorProvider.cs +++ b/src/EFCore.Relational/Query/RelationalMemberTranslatorProvider.cs @@ -4,19 +4,35 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Reflection; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Utilities; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// Provides translations for LINQ expressions by dispatching to multiple specialized member translators. + /// + /// + /// The service lifetime is . This means a single instance + /// is used by many instances. The implementation must be thread-safe. + /// This service cannot depend on services registered as . + /// + /// public class RelationalMemberTranslatorProvider : IMemberTranslatorProvider { private readonly List _plugins = new List(); private readonly List _translators = new List(); + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. public RelationalMemberTranslatorProvider([NotNull] RelationalMemberTranslatorProviderDependencies dependencies) { Check.NotNull(dependencies, nameof(dependencies)); @@ -27,6 +43,7 @@ public RelationalMemberTranslatorProvider([NotNull] RelationalMemberTranslatorPr new[] { new NullableMemberTranslator(dependencies.SqlExpressionFactory) }); } + /// public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType) { Check.NotNull(member, nameof(member)); @@ -36,6 +53,10 @@ public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member .Select(t => t.Translate(instance, member, returnType)).FirstOrDefault(t => t != null); } + /// + /// Adds additional translators which will take priority over existing registered translators. + /// + /// Translators to add. protected virtual void AddTranslators([NotNull] IEnumerable translators) { Check.NotNull(translators, nameof(translators)); diff --git a/src/EFCore.Relational/Query/RelationalMethodCallTranslatorProvider.cs b/src/EFCore.Relational/Query/RelationalMethodCallTranslatorProvider.cs index 7f2dd1d856d..d39f873987b 100644 --- a/src/EFCore.Relational/Query/RelationalMethodCallTranslatorProvider.cs +++ b/src/EFCore.Relational/Query/RelationalMethodCallTranslatorProvider.cs @@ -3,21 +3,38 @@ using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Reflection; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Utilities; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// Provides translations for LINQ expressions by dispatching to multiple specialized + /// method call translators. + /// + /// + /// The service lifetime is . This means a single instance + /// is used by many instances. The implementation must be thread-safe. + /// This service cannot depend on services registered as . + /// + /// public class RelationalMethodCallTranslatorProvider : IMethodCallTranslatorProvider { private readonly List _plugins = new List(); private readonly List _translators = new List(); private readonly ISqlExpressionFactory _sqlExpressionFactory; + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. public RelationalMethodCallTranslatorProvider([NotNull] RelationalMethodCallTranslatorProviderDependencies dependencies) { Check.NotNull(dependencies, nameof(dependencies)); @@ -42,6 +59,7 @@ public RelationalMethodCallTranslatorProvider([NotNull] RelationalMethodCallTran _sqlExpressionFactory = sqlExpressionFactory; } + /// public virtual SqlExpression Translate( IModel model, SqlExpression instance, MethodInfo method, IReadOnlyList arguments) { @@ -68,6 +86,10 @@ public virtual SqlExpression Translate( .FirstOrDefault(t => t != null); } + /// + /// Adds additional translators which will take priority over existing registered translators. + /// + /// Translators to add. protected virtual void AddTranslators([NotNull] IEnumerable translators) { Check.NotNull(translators, nameof(translators)); diff --git a/src/EFCore.Relational/Query/RelationalParameterBasedQueryTranslationPostprocessor.cs b/src/EFCore.Relational/Query/RelationalParameterBasedQueryTranslationPostprocessor.cs index e8b273856ff..a2ff2caea03 100644 --- a/src/EFCore.Relational/Query/RelationalParameterBasedQueryTranslationPostprocessor.cs +++ b/src/EFCore.Relational/Query/RelationalParameterBasedQueryTranslationPostprocessor.cs @@ -9,8 +9,22 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// A class that postprocesses the in the translated query after parementer values are known. + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public class RelationalParameterBasedQueryTranslationPostprocessor { + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. + /// A bool value indicating if relational nulls should be used. public RelationalParameterBasedQueryTranslationPostprocessor( [NotNull] RelationalParameterBasedQueryTranslationPostprocessorDependencies dependencies, bool useRelationalNulls) @@ -21,10 +35,22 @@ public RelationalParameterBasedQueryTranslationPostprocessor( UseRelationalNulls = useRelationalNulls; } + /// + /// Parameter object containing service dependencies. + /// protected virtual RelationalParameterBasedQueryTranslationPostprocessorDependencies Dependencies { get; } + /// + /// A bool value indicating if relational nulls should be used. + /// protected virtual bool UseRelationalNulls { get; } + /// + /// Optimizes a for given parameter values. + /// + /// A select expression to optimize. + /// A dictionary of parameter values to use. + /// A tuple of optimized select expression and a bool value if it can be cached. public virtual (SelectExpression, bool) Optimize( [NotNull] SelectExpression selectExpression, [NotNull] IReadOnlyDictionary parametersValues) diff --git a/src/EFCore.Relational/Query/RelationalQueryContext.cs b/src/EFCore.Relational/Query/RelationalQueryContext.cs index f96ac87719f..fa5d41231c9 100644 --- a/src/EFCore.Relational/Query/RelationalQueryContext.cs +++ b/src/EFCore.Relational/Query/RelationalQueryContext.cs @@ -9,7 +9,13 @@ namespace Microsoft.EntityFrameworkCore.Query { /// - /// The principal data structure used by a compiled relational query during execution. + /// + /// The principal data structure used by a compiled relational query during execution. + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// /// public class RelationalQueryContext : QueryContext { @@ -22,8 +28,8 @@ public class RelationalQueryContext : QueryContext /// not used in application code. /// /// - /// The dependencies to use. - /// The relational-specific dependencies to use. + /// Parameter object containing dependencies for this class. + /// Parameter object containing relational dependencies for this class. public RelationalQueryContext( [NotNull] QueryContextDependencies dependencies, [NotNull] RelationalQueryContextDependencies relationalDependencies) @@ -35,7 +41,7 @@ public RelationalQueryContext( } /// - /// Relational-specific dependencies. + /// Parameter object containing relational service dependencies. /// protected virtual RelationalQueryContextDependencies RelationalDependencies { get; } diff --git a/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs b/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs index cd7f8f1d5b0..6a439ca6c17 100644 --- a/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs @@ -9,8 +9,15 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// public class RelationalQueryTranslationPostprocessor : QueryTranslationPostprocessor { + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. + /// Parameter object containing relational dependencies for this class. + /// The query compilation context object to use. public RelationalQueryTranslationPostprocessor( [NotNull] QueryTranslationPostprocessorDependencies dependencies, [NotNull] RelationalQueryTranslationPostprocessorDependencies relationalDependencies, @@ -23,8 +30,12 @@ public RelationalQueryTranslationPostprocessor( RelationalDependencies = relationalDependencies; } + /// + /// Parameter object containing relational service dependencies. + /// protected virtual RelationalQueryTranslationPostprocessorDependencies RelationalDependencies { get; } + /// public override Expression Process(Expression query) { query = base.Process(query); @@ -40,6 +51,11 @@ public override Expression Process(Expression query) return query; } + /// + /// Optimizes the SQL expression. + /// + /// An expression to optimize. + /// An expression which has SQL optimized. [Obsolete("Use 'Optimize' method on " + nameof(RelationalParameterBasedQueryTranslationPostprocessor) + " instead. If you have a case for optimizations to be performed here, please file an issue on github.com/dotnet/efcore.")] protected virtual Expression OptimizeSqlExpression([NotNull] Expression query) => query; diff --git a/src/EFCore.Relational/Query/RelationalQueryTranslationPreprocessor.cs b/src/EFCore.Relational/Query/RelationalQueryTranslationPreprocessor.cs index 9248f1b3bd0..c3468280c7c 100644 --- a/src/EFCore.Relational/Query/RelationalQueryTranslationPreprocessor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryTranslationPreprocessor.cs @@ -8,8 +8,15 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// public class RelationalQueryTranslationPreprocessor : QueryTranslationPreprocessor { + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. + /// Parameter object containing relational dependencies for this class. + /// The query compilation context object to use. public RelationalQueryTranslationPreprocessor( [NotNull] QueryTranslationPreprocessorDependencies dependencies, [NotNull] RelationalQueryTranslationPreprocessorDependencies relationalDependencies, @@ -21,8 +28,12 @@ public RelationalQueryTranslationPreprocessor( RelationalDependencies = relationalDependencies; } + /// + /// Parameter object containing relational service dependencies. + /// protected virtual RelationalQueryTranslationPreprocessorDependencies RelationalDependencies { get; } + /// public override Expression NormalizeQueryableMethod(Expression expression) { expression = base.NormalizeQueryableMethod(expression); diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 1cf56bd16c0..4243d74a98b 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -17,6 +17,7 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// public class RelationalQueryableMethodTranslatingExpressionVisitor : QueryableMethodTranslatingExpressionVisitor { private readonly RelationalSqlTranslatingExpressionVisitor _sqlTranslator; @@ -27,6 +28,12 @@ public class RelationalQueryableMethodTranslatingExpressionVisitor : QueryableMe private readonly ISqlExpressionFactory _sqlExpressionFactory; private readonly bool _subquery; + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. + /// Parameter object containing relational dependencies for this class. + /// The query compilation context object to use. public RelationalQueryableMethodTranslatingExpressionVisitor( [NotNull] QueryableMethodTranslatingExpressionVisitorDependencies dependencies, [NotNull] RelationalQueryableMethodTranslatingExpressionVisitorDependencies relationalDependencies, @@ -48,8 +55,15 @@ public RelationalQueryableMethodTranslatingExpressionVisitor( _subquery = false; } + /// + /// Parameter object containing relational service dependencies. + /// protected virtual RelationalQueryableMethodTranslatingExpressionVisitorDependencies RelationalDependencies { get; } + /// + /// Creates a new instance of the class. + /// + /// A parent visitor to create subquery visitor for. protected RelationalQueryableMethodTranslatingExpressionVisitor( [NotNull] RelationalQueryableMethodTranslatingExpressionVisitor parentVisitor) : base(parentVisitor.Dependencies, parentVisitor.QueryCompilationContext, subquery: true) @@ -63,6 +77,7 @@ protected RelationalQueryableMethodTranslatingExpressionVisitor( _subquery = true; } + /// protected override Expression VisitExtension(Expression extensionExpression) { switch (extensionExpression) @@ -108,9 +123,11 @@ protected override Expression VisitExtension(Expression extensionExpression) } } + /// protected override QueryableMethodTranslatingExpressionVisitor CreateSubqueryVisitor() => new RelationalQueryableMethodTranslatingExpressionVisitor(this); + /// [Obsolete("Use overload which takes IEntityType.")] protected override ShapedQueryExpression CreateShapedQueryExpression(Type elementType) { @@ -122,6 +139,7 @@ protected override ShapedQueryExpression CreateShapedQueryExpression(Type elemen return CreateShapedQueryExpression(entityType, queryExpression); } + /// protected override ShapedQueryExpression CreateShapedQueryExpression(IEntityType entityType) { Check.NotNull(entityType, nameof(entityType)); @@ -140,6 +158,7 @@ private static ShapedQueryExpression CreateShapedQueryExpression(IEntityType ent typeof(ValueBuffer)), false)); + /// protected override ShapedQueryExpression TranslateAll(ShapedQueryExpression source, LambdaExpression predicate) { Check.NotNull(source, nameof(source)); @@ -165,6 +184,7 @@ protected override ShapedQueryExpression TranslateAll(ShapedQueryExpression sour new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(bool))); } + /// protected override ShapedQueryExpression TranslateAny(ShapedQueryExpression source, LambdaExpression predicate) { if (predicate != null) @@ -189,6 +209,7 @@ protected override ShapedQueryExpression TranslateAny(ShapedQueryExpression sour new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(bool))); } + /// protected override ShapedQueryExpression TranslateAverage(ShapedQueryExpression source, LambdaExpression selector, Type resultType) { Check.NotNull(source, nameof(source)); @@ -208,6 +229,7 @@ protected override ShapedQueryExpression TranslateAverage(ShapedQueryExpression : null; } + /// protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression source, Type resultType) { Check.NotNull(source, nameof(source)); @@ -218,6 +240,7 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou : source; } + /// protected override ShapedQueryExpression TranslateConcat(ShapedQueryExpression source1, ShapedQueryExpression source2) { Check.NotNull(source1, nameof(source1)); @@ -228,6 +251,7 @@ protected override ShapedQueryExpression TranslateConcat(ShapedQueryExpression s return source1; } + /// protected override ShapedQueryExpression TranslateContains(ShapedQueryExpression source, Expression item) { Check.NotNull(source, nameof(source)); @@ -252,6 +276,7 @@ protected override ShapedQueryExpression TranslateContains(ShapedQueryExpression new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(bool))); } + /// protected override ShapedQueryExpression TranslateCount(ShapedQueryExpression source, LambdaExpression predicate) { Check.NotNull(source, nameof(source)); @@ -281,6 +306,7 @@ protected override ShapedQueryExpression TranslateCount(ShapedQueryExpression so return source.UpdateShaperExpression(new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int))); } + /// protected override ShapedQueryExpression TranslateDefaultIfEmpty(ShapedQueryExpression source, Expression defaultValue) { Check.NotNull(source, nameof(source)); @@ -294,6 +320,7 @@ protected override ShapedQueryExpression TranslateDefaultIfEmpty(ShapedQueryExpr return null; } + /// protected override ShapedQueryExpression TranslateDistinct(ShapedQueryExpression source) { Check.NotNull(source, nameof(source)); @@ -303,6 +330,7 @@ protected override ShapedQueryExpression TranslateDistinct(ShapedQueryExpression return source; } + /// protected override ShapedQueryExpression TranslateElementAtOrDefault( ShapedQueryExpression source, Expression index, bool returnDefault) { @@ -312,6 +340,7 @@ protected override ShapedQueryExpression TranslateElementAtOrDefault( return null; } + /// protected override ShapedQueryExpression TranslateExcept(ShapedQueryExpression source1, ShapedQueryExpression source2) { Check.NotNull(source1, nameof(source1)); @@ -321,6 +350,7 @@ protected override ShapedQueryExpression TranslateExcept(ShapedQueryExpression s return source1; } + /// protected override ShapedQueryExpression TranslateFirstOrDefault( ShapedQueryExpression source, LambdaExpression predicate, Type returnType, bool returnDefault) { @@ -344,6 +374,7 @@ protected override ShapedQueryExpression TranslateFirstOrDefault( : source; } + /// protected override ShapedQueryExpression TranslateGroupBy( ShapedQueryExpression source, LambdaExpression keySelector, @@ -447,6 +478,7 @@ private Expression TranslateGroupingKey(Expression expression) } } + /// protected override ShapedQueryExpression TranslateGroupJoin( ShapedQueryExpression outer, ShapedQueryExpression inner, @@ -463,6 +495,7 @@ protected override ShapedQueryExpression TranslateGroupJoin( return null; } + /// protected override ShapedQueryExpression TranslateIntersect(ShapedQueryExpression source1, ShapedQueryExpression source2) { Check.NotNull(source1, nameof(source1)); @@ -473,6 +506,7 @@ protected override ShapedQueryExpression TranslateIntersect(ShapedQueryExpressio return source1; } + /// protected override ShapedQueryExpression TranslateJoin( ShapedQueryExpression outer, ShapedQueryExpression inner, @@ -504,6 +538,7 @@ protected override ShapedQueryExpression TranslateJoin( return null; } + /// protected override ShapedQueryExpression TranslateLeftJoin( ShapedQueryExpression outer, ShapedQueryExpression inner, @@ -573,6 +608,7 @@ private SqlExpression CreateJoinPredicate( private SqlExpression CreateJoinPredicate(Expression outerKey, Expression innerKey) => TranslateExpression(Expression.Equal(outerKey, innerKey)); + /// protected override ShapedQueryExpression TranslateLastOrDefault( ShapedQueryExpression source, LambdaExpression predicate, Type returnType, bool returnDefault) { @@ -604,6 +640,7 @@ protected override ShapedQueryExpression TranslateLastOrDefault( : source; } + /// protected override ShapedQueryExpression TranslateLongCount(ShapedQueryExpression source, LambdaExpression predicate) { Check.NotNull(source, nameof(source)); @@ -633,6 +670,7 @@ protected override ShapedQueryExpression TranslateLongCount(ShapedQueryExpressio return source.UpdateShaperExpression(new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(long))); } + /// protected override ShapedQueryExpression TranslateMax(ShapedQueryExpression source, LambdaExpression selector, Type resultType) { Check.NotNull(source, nameof(source)); @@ -650,6 +688,7 @@ protected override ShapedQueryExpression TranslateMax(ShapedQueryExpression sour return AggregateResultShaper(source, projection, throwWhenEmpty: true, resultType); } + /// protected override ShapedQueryExpression TranslateMin(ShapedQueryExpression source, LambdaExpression selector, Type resultType) { Check.NotNull(source, nameof(source)); @@ -667,6 +706,7 @@ protected override ShapedQueryExpression TranslateMin(ShapedQueryExpression sour return AggregateResultShaper(source, projection, throwWhenEmpty: true, resultType); } + /// protected override ShapedQueryExpression TranslateOfType(ShapedQueryExpression source, Type resultType) { Check.NotNull(source, nameof(source)); @@ -740,6 +780,7 @@ bool HasSiblings(IEntityType entityType) } } + /// protected override ShapedQueryExpression TranslateOrderBy( ShapedQueryExpression source, LambdaExpression keySelector, bool ascending) { @@ -757,6 +798,7 @@ protected override ShapedQueryExpression TranslateOrderBy( return source; } + /// protected override ShapedQueryExpression TranslateReverse(ShapedQueryExpression source) { Check.NotNull(source, nameof(source)); @@ -772,6 +814,7 @@ protected override ShapedQueryExpression TranslateReverse(ShapedQueryExpression return source; } + /// protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression source, LambdaExpression selector) { Check.NotNull(source, nameof(source)); @@ -794,6 +837,7 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s return source.UpdateShaperExpression(_projectionBindingExpressionVisitor.Translate(selectExpression, newSelectorBody)); } + /// protected override ShapedQueryExpression TranslateSelectMany( ShapedQueryExpression source, LambdaExpression collectionSelector, LambdaExpression resultSelector) { @@ -909,6 +953,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp } } + /// protected override ShapedQueryExpression TranslateSelectMany(ShapedQueryExpression source, LambdaExpression selector) { Check.NotNull(source, nameof(source)); @@ -921,6 +966,7 @@ protected override ShapedQueryExpression TranslateSelectMany(ShapedQueryExpressi return TranslateSelectMany(source, selector, resultSelector); } + /// protected override ShapedQueryExpression TranslateSingleOrDefault( ShapedQueryExpression source, LambdaExpression predicate, Type returnType, bool returnDefault) { @@ -944,6 +990,7 @@ protected override ShapedQueryExpression TranslateSingleOrDefault( : source; } + /// protected override ShapedQueryExpression TranslateSkip(ShapedQueryExpression source, Expression count) { Check.NotNull(source, nameof(source)); @@ -961,6 +1008,7 @@ protected override ShapedQueryExpression TranslateSkip(ShapedQueryExpression sou return source; } + /// protected override ShapedQueryExpression TranslateSkipWhile(ShapedQueryExpression source, LambdaExpression predicate) { Check.NotNull(source, nameof(source)); @@ -969,6 +1017,7 @@ protected override ShapedQueryExpression TranslateSkipWhile(ShapedQueryExpressio return null; } + /// protected override ShapedQueryExpression TranslateSum(ShapedQueryExpression source, LambdaExpression selector, Type resultType) { Check.NotNull(source, nameof(source)); @@ -987,6 +1036,7 @@ protected override ShapedQueryExpression TranslateSum(ShapedQueryExpression sour : null; } + /// protected override ShapedQueryExpression TranslateTake(ShapedQueryExpression source, Expression count) { Check.NotNull(source, nameof(source)); @@ -1004,6 +1054,7 @@ protected override ShapedQueryExpression TranslateTake(ShapedQueryExpression sou return source; } + /// protected override ShapedQueryExpression TranslateTakeWhile(ShapedQueryExpression source, LambdaExpression predicate) { Check.NotNull(source, nameof(source)); @@ -1012,6 +1063,7 @@ protected override ShapedQueryExpression TranslateTakeWhile(ShapedQueryExpressio return null; } + /// protected override ShapedQueryExpression TranslateThenBy(ShapedQueryExpression source, LambdaExpression keySelector, bool ascending) { Check.NotNull(source, nameof(source)); @@ -1028,6 +1080,7 @@ protected override ShapedQueryExpression TranslateThenBy(ShapedQueryExpression s return source; } + /// protected override ShapedQueryExpression TranslateUnion(ShapedQueryExpression source1, ShapedQueryExpression source2) { Check.NotNull(source1, nameof(source1)); @@ -1037,6 +1090,7 @@ protected override ShapedQueryExpression TranslateUnion(ShapedQueryExpression so return source1; } + /// protected override ShapedQueryExpression TranslateWhere(ShapedQueryExpression source, LambdaExpression predicate) { Check.NotNull(source, nameof(source)); diff --git a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs index 4d25c2dd01e..07cd8034b2d 100644 --- a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs @@ -16,6 +16,7 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// public partial class RelationalShapedQueryCompilingExpressionVisitor : ShapedQueryCompilingExpressionVisitor { private readonly Type _contextType; @@ -24,6 +25,12 @@ public partial class RelationalShapedQueryCompilingExpressionVisitor : ShapedQue private readonly bool _detailedErrorsEnabled; private readonly bool _useRelationalNulls; + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. + /// Parameter object containing relational dependencies for this class. + /// The query compilation context object to use. public RelationalShapedQueryCompilingExpressionVisitor( [NotNull] ShapedQueryCompilingExpressionVisitorDependencies dependencies, [NotNull] RelationalShapedQueryCompilingExpressionVisitorDependencies relationalDependencies, @@ -41,8 +48,12 @@ public RelationalShapedQueryCompilingExpressionVisitor( _useRelationalNulls = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).UseRelationalNulls; } + /// + /// Parameter object containing relational service dependencies. + /// protected virtual RelationalShapedQueryCompilingExpressionVisitorDependencies RelationalDependencies { get; } + /// protected override Expression VisitShapedQuery(ShapedQueryExpression shapedQueryExpression) { Check.NotNull(shapedQueryExpression, nameof(shapedQueryExpression)); diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs index 1a8116167c0..8c5f1c6000b 100644 --- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs @@ -17,6 +17,15 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// A class that translates expressions to corresponding SQL representation. + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public class RelationalSqlTranslatingExpressionVisitor : ExpressionVisitor { private const string RuntimeParameterPrefix = QueryCompilationContext.QueryParameterPrefix + "entity_equality_"; @@ -32,6 +41,12 @@ public class RelationalSqlTranslatingExpressionVisitor : ExpressionVisitor private readonly QueryableMethodTranslatingExpressionVisitor _queryableMethodTranslatingExpressionVisitor; private readonly SqlTypeMappingVerifyingExpressionVisitor _sqlTypeMappingVerifyingExpressionVisitor; + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. + /// The query compilation context object to use. + /// A parent queryable method translating expression visitor to translate subquery. public RelationalSqlTranslatingExpressionVisitor( [NotNull] RelationalSqlTranslatingExpressionVisitorDependencies dependencies, [NotNull] QueryCompilationContext queryCompilationContext, @@ -49,8 +64,16 @@ public RelationalSqlTranslatingExpressionVisitor( _sqlTypeMappingVerifyingExpressionVisitor = new SqlTypeMappingVerifyingExpressionVisitor(); } + /// + /// Parameter object containing service dependencies. + /// protected virtual RelationalSqlTranslatingExpressionVisitorDependencies Dependencies { get; } + /// + /// Translates an expression to an equivalent SQL representation. + /// + /// An expression to translate. + /// A SQL translation of the given expression. public virtual SqlExpression Translate([NotNull] Expression expression) { Check.NotNull(expression, nameof(expression)); @@ -82,6 +105,11 @@ public virtual SqlExpression Translate([NotNull] Expression expression) return null; } + /// + /// Translates Average over an expression to an equivalent SQL representation. + /// + /// An expression to translate Average over. + /// A SQL translation of Average over the given expression. public virtual SqlExpression TranslateAverage([NotNull] Expression expression) { Check.NotNull(expression, nameof(expression)); @@ -123,6 +151,11 @@ public virtual SqlExpression TranslateAverage([NotNull] Expression expression) sqlExpression.TypeMapping); } + /// + /// Translates Count over an expression to an equivalent SQL representation. + /// + /// An expression to translate Count over. + /// A SQL translation of Count over the given expression. public virtual SqlExpression TranslateCount([CanBeNull] Expression expression = null) { if (expression != null) @@ -140,6 +173,11 @@ public virtual SqlExpression TranslateCount([CanBeNull] Expression expression = typeof(int))); } + /// + /// Translates LongCount over an expression to an equivalent SQL representation. + /// + /// An expression to translate LongCount over. + /// A SQL translation of LongCount over the given expression. public virtual SqlExpression TranslateLongCount([CanBeNull] Expression expression = null) { if (expression != null) @@ -157,6 +195,11 @@ public virtual SqlExpression TranslateLongCount([CanBeNull] Expression expressio typeof(long))); } + /// + /// Translates Max over an expression to an equivalent SQL representation. + /// + /// An expression to translate Max over. + /// A SQL translation of Max over the given expression. public virtual SqlExpression TranslateMax([NotNull] Expression expression) { Check.NotNull(expression, nameof(expression)); @@ -177,6 +220,11 @@ public virtual SqlExpression TranslateMax([NotNull] Expression expression) : null; } + /// + /// Translates Min over an expression to an equivalent SQL representation. + /// + /// An expression to translate Min over. + /// A SQL translation of Min over the given expression. public virtual SqlExpression TranslateMin([NotNull] Expression expression) { Check.NotNull(expression, nameof(expression)); @@ -197,6 +245,11 @@ public virtual SqlExpression TranslateMin([NotNull] Expression expression) : null; } + /// + /// Translates Sum over an expression to an equivalent SQL representation. + /// + /// An expression to translate Sum over. + /// A SQL translation of Sum over the given expression. public virtual SqlExpression TranslateSum([NotNull] Expression expression) { Check.NotNull(expression, nameof(expression)); @@ -232,6 +285,7 @@ public virtual SqlExpression TranslateSum([NotNull] Expression expression) sqlExpression.TypeMapping); } + /// protected override Expression VisitBinary(BinaryExpression binaryExpression) { Check.NotNull(binaryExpression, nameof(binaryExpression)); @@ -277,6 +331,7 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) null); } + /// protected override Expression VisitConditional(ConditionalExpression conditionalExpression) { Check.NotNull(conditionalExpression, nameof(conditionalExpression)); @@ -292,9 +347,11 @@ protected override Expression VisitConditional(ConditionalExpression conditional : _sqlExpressionFactory.Case(new[] { new CaseWhenClause(sqlTest, sqlIfTrue) }, sqlIfFalse); } + /// protected override Expression VisitConstant(ConstantExpression constantExpression) => new SqlConstantExpression(Check.NotNull(constantExpression, nameof(constantExpression)), null); + /// protected override Expression VisitExtension(Expression extensionExpression) { Check.NotNull(extensionExpression, nameof(extensionExpression)); @@ -320,10 +377,14 @@ protected override Expression VisitExtension(Expression extensionExpression) } } + /// protected override Expression VisitInvocation(InvocationExpression invocationExpression) => null; + /// protected override Expression VisitLambda(Expression lambdaExpression) => null; + /// protected override Expression VisitListInit(ListInitExpression listInitExpression) => null; + /// protected override Expression VisitMember(MemberExpression memberExpression) { Check.NotNull(memberExpression, nameof(memberExpression)); @@ -336,9 +397,11 @@ protected override Expression VisitMember(MemberExpression memberExpression) : Dependencies.MemberTranslatorProvider.Translate(sqlInnerExpression, memberExpression.Member, memberExpression.Type)); } + /// protected override Expression VisitMemberInit(MemberInitExpression memberInitExpression) => GetConstantOrNull(Check.NotNull(memberInitExpression, nameof(memberInitExpression))); + /// protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { Check.NotNull(methodCallExpression, nameof(methodCallExpression)); @@ -565,16 +628,20 @@ static Expression RemoveObjectConvert(Expression expression) : expression; } + /// protected override Expression VisitNew(NewExpression newExpression) => GetConstantOrNull(Check.NotNull(newExpression, nameof(newExpression))); + /// protected override Expression VisitNewArray(NewArrayExpression newArrayExpression) => null; + /// protected override Expression VisitParameter(ParameterExpression parameterExpression) => parameterExpression.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal) == true ? new SqlParameterExpression(Check.NotNull(parameterExpression, nameof(parameterExpression)), null) : null; + /// protected override Expression VisitTypeBinary(TypeBinaryExpression typeBinaryExpression) { Check.NotNull(typeBinaryExpression, nameof(typeBinaryExpression)); @@ -612,6 +679,7 @@ protected override Expression VisitTypeBinary(TypeBinaryExpression typeBinaryExp return null; } + /// protected override Expression VisitUnary(UnaryExpression unaryExpression) { Check.NotNull(unaryExpression, nameof(unaryExpression)); diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs index 4a36379bcbd..c613620f7bb 100644 --- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs +++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs @@ -16,11 +16,16 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// public class SqlExpressionFactory : ISqlExpressionFactory { private readonly IRelationalTypeMappingSource _typeMappingSource; private readonly RelationalTypeMapping _boolTypeMapping; + /// + /// Creates a new instance of the class. + /// + /// Parameter object containing dependencies for this class. public SqlExpressionFactory([NotNull] SqlExpressionFactoryDependencies dependencies) { Check.NotNull(dependencies, nameof(dependencies)); @@ -29,6 +34,7 @@ public SqlExpressionFactory([NotNull] SqlExpressionFactoryDependencies dependenc _boolTypeMapping = _typeMappingSource.FindMapping(typeof(bool)); } + /// public virtual SqlExpression ApplyDefaultTypeMapping(SqlExpression sqlExpression) { if (sqlExpression == null @@ -47,6 +53,7 @@ public virtual SqlExpression ApplyDefaultTypeMapping(SqlExpression sqlExpression return ApplyTypeMapping(sqlExpression, _typeMappingSource.FindMapping(sqlExpression.Type)); } + /// public virtual SqlExpression ApplyTypeMapping(SqlExpression sqlExpression, RelationalTypeMapping typeMapping) { if (sqlExpression == null @@ -213,6 +220,7 @@ private SqlExpression ApplyTypeMappingOnSqlBinary( resultTypeMapping); } + /// public virtual SqlBinaryExpression MakeBinary( ExpressionType operatorType, SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping) { @@ -239,6 +247,7 @@ public virtual SqlBinaryExpression MakeBinary( new SqlBinaryExpression(operatorType, left, right, returnType, null), typeMapping); } + /// public virtual SqlBinaryExpression Equal(SqlExpression left, SqlExpression right) { Check.NotNull(left, nameof(left)); @@ -247,6 +256,7 @@ public virtual SqlBinaryExpression Equal(SqlExpression left, SqlExpression right return MakeBinary(ExpressionType.Equal, left, right, null); } + /// public virtual SqlBinaryExpression NotEqual(SqlExpression left, SqlExpression right) { Check.NotNull(left, nameof(left)); @@ -255,6 +265,7 @@ public virtual SqlBinaryExpression NotEqual(SqlExpression left, SqlExpression ri return MakeBinary(ExpressionType.NotEqual, left, right, null); } + /// public virtual SqlBinaryExpression GreaterThan(SqlExpression left, SqlExpression right) { Check.NotNull(left, nameof(left)); @@ -263,6 +274,7 @@ public virtual SqlBinaryExpression GreaterThan(SqlExpression left, SqlExpression return MakeBinary(ExpressionType.GreaterThan, left, right, null); } + /// public virtual SqlBinaryExpression GreaterThanOrEqual(SqlExpression left, SqlExpression right) { Check.NotNull(left, nameof(left)); @@ -271,6 +283,7 @@ public virtual SqlBinaryExpression GreaterThanOrEqual(SqlExpression left, SqlExp return MakeBinary(ExpressionType.GreaterThanOrEqual, left, right, null); } + /// public virtual SqlBinaryExpression LessThan(SqlExpression left, SqlExpression right) { Check.NotNull(left, nameof(left)); @@ -279,6 +292,7 @@ public virtual SqlBinaryExpression LessThan(SqlExpression left, SqlExpression ri return MakeBinary(ExpressionType.LessThan, left, right, null); } + /// public virtual SqlBinaryExpression LessThanOrEqual(SqlExpression left, SqlExpression right) { Check.NotNull(left, nameof(left)); @@ -287,6 +301,7 @@ public virtual SqlBinaryExpression LessThanOrEqual(SqlExpression left, SqlExpres return MakeBinary(ExpressionType.LessThanOrEqual, left, right, null); } + /// public virtual SqlBinaryExpression AndAlso(SqlExpression left, SqlExpression right) { Check.NotNull(left, nameof(left)); @@ -295,6 +310,7 @@ public virtual SqlBinaryExpression AndAlso(SqlExpression left, SqlExpression rig return MakeBinary(ExpressionType.AndAlso, left, right, null); } + /// public virtual SqlBinaryExpression OrElse(SqlExpression left, SqlExpression right) { Check.NotNull(left, nameof(left)); @@ -303,6 +319,7 @@ public virtual SqlBinaryExpression OrElse(SqlExpression left, SqlExpression righ return MakeBinary(ExpressionType.OrElse, left, right, null); } + /// public virtual SqlBinaryExpression Add(SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping = null) { Check.NotNull(left, nameof(left)); @@ -311,6 +328,7 @@ public virtual SqlBinaryExpression Add(SqlExpression left, SqlExpression right, return MakeBinary(ExpressionType.Add, left, right, typeMapping); } + /// public virtual SqlBinaryExpression Subtract(SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping = null) { Check.NotNull(left, nameof(left)); @@ -319,6 +337,7 @@ public virtual SqlBinaryExpression Subtract(SqlExpression left, SqlExpression ri return MakeBinary(ExpressionType.Subtract, left, right, typeMapping); } + /// public virtual SqlBinaryExpression Multiply(SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping = null) { Check.NotNull(left, nameof(left)); @@ -327,6 +346,7 @@ public virtual SqlBinaryExpression Multiply(SqlExpression left, SqlExpression ri return MakeBinary(ExpressionType.Multiply, left, right, typeMapping); } + /// public virtual SqlBinaryExpression Divide(SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping = null) { Check.NotNull(left, nameof(left)); @@ -335,6 +355,7 @@ public virtual SqlBinaryExpression Divide(SqlExpression left, SqlExpression righ return MakeBinary(ExpressionType.Divide, left, right, typeMapping); } + /// public virtual SqlBinaryExpression Modulo(SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping = null) { Check.NotNull(left, nameof(left)); @@ -343,6 +364,7 @@ public virtual SqlBinaryExpression Modulo(SqlExpression left, SqlExpression righ return MakeBinary(ExpressionType.Modulo, left, right, typeMapping); } + /// public virtual SqlBinaryExpression And(SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping = null) { Check.NotNull(left, nameof(left)); @@ -351,6 +373,7 @@ public virtual SqlBinaryExpression And(SqlExpression left, SqlExpression right, return MakeBinary(ExpressionType.And, left, right, typeMapping); } + /// public virtual SqlBinaryExpression Or(SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping = null) { Check.NotNull(left, nameof(left)); @@ -359,6 +382,7 @@ public virtual SqlBinaryExpression Or(SqlExpression left, SqlExpression right, R return MakeBinary(ExpressionType.Or, left, right, typeMapping); } + /// public virtual SqlFunctionExpression Coalesce(SqlExpression left, SqlExpression right, RelationalTypeMapping typeMapping = null) { Check.NotNull(left, nameof(left)); @@ -385,6 +409,7 @@ public virtual SqlFunctionExpression Coalesce(SqlExpression left, SqlExpression inferredTypeMapping); } + /// public virtual SqlUnaryExpression MakeUnary( ExpressionType operatorType, SqlExpression operand, Type type, RelationalTypeMapping typeMapping = null) { @@ -395,6 +420,7 @@ public virtual SqlUnaryExpression MakeUnary( return (SqlUnaryExpression)ApplyTypeMapping(new SqlUnaryExpression(operatorType, operand, type, null), typeMapping); } + /// public virtual SqlUnaryExpression IsNull(SqlExpression operand) { Check.NotNull(operand, nameof(operand)); @@ -402,6 +428,7 @@ public virtual SqlUnaryExpression IsNull(SqlExpression operand) return MakeUnary(ExpressionType.Equal, operand, typeof(bool)); } + /// public virtual SqlUnaryExpression IsNotNull(SqlExpression operand) { Check.NotNull(operand, nameof(operand)); @@ -409,6 +436,7 @@ public virtual SqlUnaryExpression IsNotNull(SqlExpression operand) return MakeUnary(ExpressionType.NotEqual, operand, typeof(bool)); } + /// public virtual SqlUnaryExpression Convert(SqlExpression operand, Type type, RelationalTypeMapping typeMapping = null) { Check.NotNull(operand, nameof(operand)); @@ -417,6 +445,7 @@ public virtual SqlUnaryExpression Convert(SqlExpression operand, Type type, Rela return MakeUnary(ExpressionType.Convert, operand, type, typeMapping); } + /// public virtual SqlUnaryExpression Not(SqlExpression operand) { Check.NotNull(operand, nameof(operand)); @@ -424,6 +453,7 @@ public virtual SqlUnaryExpression Not(SqlExpression operand) return MakeUnary(ExpressionType.Not, operand, operand.Type, operand.TypeMapping); } + /// public virtual SqlUnaryExpression Negate(SqlExpression operand) { Check.NotNull(operand, nameof(operand)); @@ -431,6 +461,7 @@ public virtual SqlUnaryExpression Negate(SqlExpression operand) return MakeUnary(ExpressionType.Negate, operand, operand.Type, operand.TypeMapping); } + /// public virtual CaseExpression Case(SqlExpression operand, params CaseWhenClause[] whenClauses) { Check.NotNull(operand, nameof(operand)); @@ -459,6 +490,7 @@ public virtual CaseExpression Case(SqlExpression operand, params CaseWhenClause[ return new CaseExpression(operand, typeMappedWhenClauses); } + /// public virtual CaseExpression Case(IReadOnlyList whenClauses, SqlExpression elseResult) { Check.NotNull(whenClauses, nameof(whenClauses)); @@ -480,6 +512,7 @@ public virtual CaseExpression Case(IReadOnlyList whenClauses, Sq return new CaseExpression(typeMappedWhenClauses, elseResult); } + /// [Obsolete("Use overload that explicitly specifies value for 'argumentsPropagateNullability' argument.")] public virtual SqlFunctionExpression Function( string name, @@ -488,6 +521,7 @@ public virtual SqlFunctionExpression Function( RelationalTypeMapping typeMapping = null) => Function(name, arguments, nullable: true, argumentsPropagateNullability: arguments.Select(a => false), returnType, typeMapping); + /// [Obsolete("Use overload that explicitly specifies value for 'argumentsPropagateNullability' argument.")] public virtual SqlFunctionExpression Function( string schema, @@ -497,6 +531,7 @@ public virtual SqlFunctionExpression Function( RelationalTypeMapping typeMapping = null) => Function(schema, name, arguments, nullable: true, argumentsPropagateNullability: arguments.Select(a => false), returnType, typeMapping); + /// [Obsolete("Use overload that explicitly specifies values for 'instancePropagatesNullability' and 'argumentsPropagateNullability' arguments.")] public virtual SqlFunctionExpression Function( SqlExpression instance, @@ -514,18 +549,22 @@ public virtual SqlFunctionExpression Function( returnType, typeMapping); + /// [Obsolete("Use overload that explicitly specifies value for 'nullable' argument.")] public virtual SqlFunctionExpression Function(string name, Type returnType, RelationalTypeMapping typeMapping = null) => Function(name, nullable: true, returnType, typeMapping); + /// [Obsolete("Use overload that explicitly specifies value for 'nullable' argument.")] public virtual SqlFunctionExpression Function(string schema, string name, Type returnType, RelationalTypeMapping typeMapping = null) => Function(schema, name, nullable: true, returnType, typeMapping); + /// [Obsolete("Use overload that explicitly specifies value for 'instancePropagatesNullability' argument.")] public virtual SqlFunctionExpression Function(SqlExpression instance, string name, Type returnType, RelationalTypeMapping typeMapping = null) => Function(instance, name, nullable: true, instancePropagatesNullability: false, returnType, typeMapping); + /// public virtual SqlFunctionExpression Function( string name, IEnumerable arguments, @@ -549,6 +588,7 @@ public virtual SqlFunctionExpression Function( return new SqlFunctionExpression(name, typeMappedArguments, nullable, argumentsPropagateNullability, returnType, typeMapping); } + /// public virtual SqlFunctionExpression Function( string schema, string name, @@ -572,6 +612,7 @@ public virtual SqlFunctionExpression Function( return new SqlFunctionExpression(schema, name, typeMappedArguments, nullable, argumentsPropagateNullability, returnType, typeMapping); } + /// public virtual SqlFunctionExpression Function( SqlExpression instance, string name, @@ -598,6 +639,7 @@ public virtual SqlFunctionExpression Function( return new SqlFunctionExpression(instance, name, typeMappedArguments, nullable, instancePropagatesNullability, argumentsPropagateNullability, returnType, typeMapping); } + /// public virtual SqlFunctionExpression Function(string name, bool nullable, Type returnType, RelationalTypeMapping typeMapping = null) { Check.NotEmpty(name, nameof(name)); @@ -606,6 +648,7 @@ public virtual SqlFunctionExpression Function(string name, bool nullable, Type r return new SqlFunctionExpression(name, nullable, returnType, typeMapping); } + /// public virtual SqlFunctionExpression Function(string schema, string name, bool nullable, Type returnType, RelationalTypeMapping typeMapping = null) { Check.NotEmpty(schema, nameof(schema)); @@ -615,6 +658,7 @@ public virtual SqlFunctionExpression Function(string schema, string name, bool n return new SqlFunctionExpression(schema, name, nullable, returnType, typeMapping); } + /// public virtual SqlFunctionExpression Function( SqlExpression instance, string name, @@ -630,6 +674,7 @@ public virtual SqlFunctionExpression Function( return new SqlFunctionExpression(ApplyDefaultTypeMapping(instance), name, nullable, instancePropagatesNullability, returnType, typeMapping); } + /// public virtual ExistsExpression Exists(SelectExpression subquery, bool negated) { Check.NotNull(subquery, nameof(subquery)); @@ -637,6 +682,7 @@ public virtual ExistsExpression Exists(SelectExpression subquery, bool negated) return new ExistsExpression(subquery, negated, _boolTypeMapping); } + /// public virtual InExpression In(SqlExpression item, SqlExpression values, bool negated) { Check.NotNull(item, nameof(item)); @@ -647,9 +693,10 @@ public virtual InExpression In(SqlExpression item, SqlExpression values, bool ne item = ApplyTypeMapping(item, typeMapping); values = ApplyTypeMapping(values, typeMapping); - return new InExpression(item, negated, values, _boolTypeMapping); + return new InExpression(item, values, negated, _boolTypeMapping); } + /// public virtual InExpression In(SqlExpression item, SelectExpression subquery, bool negated) { Check.NotNull(item, nameof(item)); @@ -664,9 +711,10 @@ public virtual InExpression In(SqlExpression item, SelectExpression subquery, bo } item = ApplyTypeMapping(item, typeMapping); - return new InExpression(item, negated, subquery, _boolTypeMapping); + return new InExpression(item, subquery, negated, _boolTypeMapping); } + /// public virtual LikeExpression Like(SqlExpression match, SqlExpression pattern, SqlExpression escapeChar = null) { Check.NotNull(match, nameof(match)); @@ -675,6 +723,7 @@ public virtual LikeExpression Like(SqlExpression match, SqlExpression pattern, S return (LikeExpression)ApplyDefaultTypeMapping(new LikeExpression(match, pattern, escapeChar, null)); } + /// public virtual SqlFragmentExpression Fragment(string sql) { Check.NotNull(sql, nameof(sql)); @@ -682,11 +731,14 @@ public virtual SqlFragmentExpression Fragment(string sql) return new SqlFragmentExpression(sql); } + /// public virtual SqlConstantExpression Constant(object value, RelationalTypeMapping typeMapping = null) => new SqlConstantExpression(Expression.Constant(value), typeMapping); + /// public virtual SelectExpression Select(SqlExpression projection) => new SelectExpression(projection); + /// public virtual SelectExpression Select(IEntityType entityType) { Check.NotNull(entityType, nameof(entityType)); @@ -697,6 +749,7 @@ public virtual SelectExpression Select(IEntityType entityType) return selectExpression; } + /// public virtual SelectExpression Select(IEntityType entityType, TableExpressionBase tableExpressionBase) { Check.NotNull(entityType, nameof(entityType)); @@ -708,6 +761,7 @@ public virtual SelectExpression Select(IEntityType entityType, TableExpressionBa return selectExpression; } + /// public virtual SelectExpression Select(IEntityType entityType, string sql, Expression sqlArguments) { Check.NotNull(entityType, nameof(entityType)); @@ -929,9 +983,11 @@ private EntityProjectionExpression GetMappedEntityProjectionExpression(SelectExp private SqlExpression IsNotNull(IProperty property, EntityProjectionExpression entityProjection) => IsNotNull(entityProjection.BindProperty(property)); + /// [Obsolete("Use IRelationalTypeMappingSource directly.")] public virtual RelationalTypeMapping GetTypeMappingForValue(object value) => _typeMappingSource.GetMappingForValue(value); + /// [Obsolete("Use IRelationalTypeMappingSource directly.")] public virtual RelationalTypeMapping FindMapping(Type type) => _typeMappingSource.FindMapping(Check.NotNull(type, nameof(type))); } diff --git a/src/EFCore.Relational/Query/SqlExpressionVisitor.cs b/src/EFCore.Relational/Query/SqlExpressionVisitor.cs index 7b8351831cb..4d26930f96f 100644 --- a/src/EFCore.Relational/Query/SqlExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/SqlExpressionVisitor.cs @@ -8,8 +8,18 @@ namespace Microsoft.EntityFrameworkCore.Query { + /// + /// + /// A class that visits a SQL expression tree. + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public abstract class SqlExpressionVisitor : ExpressionVisitor { + /// protected override Expression VisitExtension(Expression extensionExpression) { Check.NotNull(extensionExpression, nameof(extensionExpression)); @@ -108,33 +118,173 @@ protected override Expression VisitExtension(Expression extensionExpression) return base.VisitExtension(extensionExpression); } + /// + /// Visits the children of the case expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitCase([NotNull] CaseExpression caseExpression); + /// + /// Visits the children of the collate expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitCollate([NotNull] CollateExpression collateExpression); + /// + /// Visits the children of the column expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitColumn([NotNull] ColumnExpression columnExpression); + /// + /// Visits the children of the cross apply expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitCrossApply([NotNull] CrossApplyExpression crossApplyExpression); + /// + /// Visits the children of the cross join expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitCrossJoin([NotNull] CrossJoinExpression crossJoinExpression); + /// + /// Visits the children of the except expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitExcept([NotNull] ExceptExpression exceptExpression); + /// + /// Visits the children of the exists expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitExists([NotNull] ExistsExpression existsExpression); + /// + /// Visits the children of the from sql expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitFromSql([NotNull] FromSqlExpression fromSqlExpression); + /// + /// Visits the children of the in expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitIn([NotNull] InExpression inExpression); + /// + /// Visits the children of the intersect expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitIntersect([NotNull] IntersectExpression intersectExpression); + /// + /// Visits the children of the like expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitLike([NotNull] LikeExpression likeExpression); + /// + /// Visits the children of the inner join expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitInnerJoin([NotNull] InnerJoinExpression innerJoinExpression); + /// + /// Visits the children of the left join expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitLeftJoin([NotNull] LeftJoinExpression leftJoinExpression); + /// + /// Visits the children of the ordering expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitOrdering([NotNull] OrderingExpression orderingExpression); + /// + /// Visits the children of the outer apply expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitOuterApply([NotNull] OuterApplyExpression outerApplyExpression); + /// + /// Visits the children of the projection expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitProjection([NotNull] ProjectionExpression projectionExpression); - protected abstract Expression VisitTableValuedFunction([NotNull] TableValuedFunctionExpression queryableFunctionExpression); + /// + /// Visits the children of the table valued function expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. + protected abstract Expression VisitTableValuedFunction([NotNull] TableValuedFunctionExpression tableValuedFunctionExpression); + /// + /// Visits the children of the row number expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitRowNumber([NotNull] RowNumberExpression rowNumberExpression); + /// + /// Visits the children of the scalar subquery expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitScalarSubquery([NotNull] ScalarSubqueryExpression scalarSubqueryExpression); + /// + /// Visits the children of the select expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitSelect([NotNull] SelectExpression selectExpression); + /// + /// Visits the children of the sql binary expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitSqlBinary([NotNull] SqlBinaryExpression sqlBinaryExpression); + /// + /// Visits the children of the sql constant expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitSqlConstant([NotNull] SqlConstantExpression sqlConstantExpression); + /// + /// Visits the children of the sql fragent expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitSqlFragment([NotNull] SqlFragmentExpression sqlFragmentExpression); + /// + /// Visits the children of the sql function expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitSqlFunction([NotNull] SqlFunctionExpression sqlFunctionExpression); + /// + /// Visits the children of the sql parameter expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitSqlParameter([NotNull] SqlParameterExpression sqlParameterExpression); + /// + /// Visits the children of the sql unary expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitSqlUnary([NotNull] SqlUnaryExpression sqlUnaryExpression); + /// + /// Visits the children of the table expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitTable([NotNull] TableExpression tableExpression); + /// + /// Visits the children of the union expression. + /// + /// The expression to visit. + /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. protected abstract Expression VisitUnion([NotNull] UnionExpression unionExpression); } } diff --git a/src/EFCore.Relational/Query/SqlExpressions/InExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/InExpression.cs index 6ca82177db3..3ce433b26e5 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/InExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/InExpression.cs @@ -29,15 +29,14 @@ public class InExpression : SqlExpression /// A value indicating if the item should be present in the values or absent. /// A subquery in which item is searched. /// The associated with the expression. + [Obsolete("Use overload which passes negated argument after subquery argument.")] public InExpression( [NotNull] SqlExpression item, bool negated, [NotNull] SelectExpression subquery, [CanBeNull] RelationalTypeMapping typeMapping) - : this(item, negated, null, subquery, typeMapping) + : this(Check.NotNull(item, nameof(item)), null, Check.NotNull(subquery, nameof(subquery)), negated, typeMapping) { - Check.NotNull(item, nameof(item)); - Check.NotNull(subquery, nameof(subquery)); } /// @@ -47,26 +46,56 @@ public InExpression( /// A value indicating if the item should be present in the values or absent. /// A list of values in which item is searched. /// The associated with the expression. + [Obsolete("Use overload which passes negated argument after values argument.")] public InExpression( [NotNull] SqlExpression item, bool negated, [NotNull] SqlExpression values, [CanBeNull] RelationalTypeMapping typeMapping) - : this(item, negated, values, null, typeMapping) + : this(Check.NotNull(item, nameof(item)), Check.NotNull(values, nameof(values)), null, negated, typeMapping) + { + } + + /// + /// Creates a new instance of the class. + /// + /// An item to look into values. + /// A subquery in which item is searched. + /// A value indicating if the item should be present in the values or absent. + /// The associated with the expression. + public InExpression( + [NotNull] SqlExpression item, + [NotNull] SelectExpression subquery, + bool negated, + [CanBeNull] RelationalTypeMapping typeMapping) + : this(Check.NotNull(item, nameof(item)), null, Check.NotNull(subquery, nameof(subquery)), negated, typeMapping) + { + } + + /// + /// Creates a new instance of the class. + /// + /// An item to look into values. + /// A list of values in which item is searched. + /// A value indicating if the item should be present in the values or absent. + /// The associated with the expression. + public InExpression( + [NotNull] SqlExpression item, + [NotNull] SqlExpression values, + bool negated, + [CanBeNull] RelationalTypeMapping typeMapping) + : this(Check.NotNull(item, nameof(item)), Check.NotNull(values, nameof(values)), null, negated, typeMapping) { - Check.NotNull(item, nameof(item)); - Check.NotNull(values, nameof(values)); } private InExpression( - SqlExpression item, bool negated, SqlExpression values, SelectExpression subquery, - RelationalTypeMapping typeMapping) + SqlExpression item, SqlExpression values, SelectExpression subquery, bool negated, RelationalTypeMapping typeMapping) : base(typeof(bool), typeMapping) { Item = item; - IsNegated = negated; Subquery = subquery; Values = values; + IsNegated = negated; } /// @@ -102,7 +131,7 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) /// Negates this expression by changing presence/absence state indicated by . /// /// An expression which is negated form of this expression. - public virtual InExpression Negate() => new InExpression(Item, !IsNegated, Values, Subquery, TypeMapping); + public virtual InExpression Negate() => new InExpression(Item, Values, Subquery, !IsNegated, TypeMapping); /// /// Creates a new expression that is like this one, but using the supplied children. If all of the children are the same, it will @@ -124,7 +153,7 @@ public virtual InExpression Update( } return item != Item || subquery != Subquery || values != Values - ? new InExpression(item, IsNegated, values, subquery, TypeMapping) + ? new InExpression(item, values, subquery, IsNegated, TypeMapping) : this; } diff --git a/src/EFCore.Relational/Query/SqlExpressions/SqlConstantExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SqlConstantExpression.cs index ec4af6614ca..6b2512b19ad 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SqlConstantExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SqlConstantExpression.cs @@ -26,7 +26,7 @@ public class SqlConstantExpression : SqlExpression /// /// Creates a new instance of the class. /// - /// A + /// A . /// The associated with the expression. public SqlConstantExpression([NotNull] ConstantExpression constantExpression, [CanBeNull] RelationalTypeMapping typeMapping) : base(Check.NotNull(constantExpression, nameof(constantExpression)).Type, typeMapping) diff --git a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseColumn.cs b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseColumn.cs index 47ff96a103d..1c7c80832db 100644 --- a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseColumn.cs +++ b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseColumn.cs @@ -15,6 +15,12 @@ namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata /// public class DatabaseColumn : Annotatable { + /// + /// Creates a new instance of the class. + /// + /// The table containing this column. + /// The name of the column. + /// The store type of the column. public DatabaseColumn([NotNull] DatabaseTable table, [NotNull] string name, [NotNull] string storeType) { Table = table; @@ -75,6 +81,7 @@ public DatabaseColumn([NotNull] DatabaseTable table, [NotNull] string name, [Not /// public virtual ValueGenerated? ValueGenerated { get; set; } + /// public override string ToString() => Name; } } diff --git a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseForeignKey.cs b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseForeignKey.cs index cc0c3cfd2a6..d78b6260c3b 100644 --- a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseForeignKey.cs +++ b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseForeignKey.cs @@ -15,6 +15,12 @@ namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata /// public class DatabaseForeignKey : Annotatable { + /// + /// Creates a new instance of the class. + /// + /// The table containing this foreign key constraint. + /// The name of the foreign key constraint. + /// The table to which the columns are constrained. public DatabaseForeignKey( [NotNull] DatabaseTable table, [CanBeNull] string? name, @@ -59,6 +65,7 @@ public DatabaseForeignKey( /// public virtual ReferentialAction? OnDelete { get; set; } + /// public override string ToString() => Name ?? ""; } } diff --git a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseIndex.cs b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseIndex.cs index 44000493ff6..717fb5f9546 100644 --- a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseIndex.cs +++ b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseIndex.cs @@ -14,6 +14,11 @@ namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata /// public class DatabaseIndex : Annotatable { + /// + /// Creates a new instance of the class. + /// + /// The table containing this index. + /// The name of the index. public DatabaseIndex([NotNull] DatabaseTable table, [CanBeNull] string? name) { Table = table; @@ -46,6 +51,7 @@ public DatabaseIndex([NotNull] DatabaseTable table, [CanBeNull] string? name) /// public virtual string? Filter { get; [param: CanBeNull] set; } + /// public override string ToString() => Name ?? ""; } } diff --git a/src/EFCore.Relational/Scaffolding/Metadata/DatabasePrimaryKey.cs b/src/EFCore.Relational/Scaffolding/Metadata/DatabasePrimaryKey.cs index 0b3f5aa3d6e..dd848c8be3c 100644 --- a/src/EFCore.Relational/Scaffolding/Metadata/DatabasePrimaryKey.cs +++ b/src/EFCore.Relational/Scaffolding/Metadata/DatabasePrimaryKey.cs @@ -14,6 +14,11 @@ namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata /// public class DatabasePrimaryKey : Annotatable { + /// + /// Creates a new instance of the class. + /// + /// The table on which this primary key is defined. + /// The name of the primary key. public DatabasePrimaryKey([NotNull] DatabaseTable table, [CanBeNull] string? name) { Table = table; @@ -36,6 +41,7 @@ public DatabasePrimaryKey([NotNull] DatabaseTable table, [CanBeNull] string? nam /// public virtual IList Columns { get; } + /// public override string ToString() => Name ?? ""; } } diff --git a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseSequence.cs b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseSequence.cs index 6488b8bcb6f..5f33ad9aa4e 100644 --- a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseSequence.cs +++ b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseSequence.cs @@ -13,6 +13,11 @@ namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata /// public class DatabaseSequence : Annotatable { + /// + /// Creates a new instance of the class. + /// + /// The database containing this sequence. + /// The name of the sequence. public DatabaseSequence([NotNull] DatabaseModel database, [NotNull] string name) { Database = database; @@ -64,6 +69,7 @@ public DatabaseSequence([NotNull] DatabaseModel database, [NotNull] string name) /// public virtual bool? IsCyclic { get; set; } + /// public override string ToString() => Schema == null ? Name : $"{Schema}.{Name}"; } } diff --git a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseTable.cs b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseTable.cs index 1c28c1fbc18..3b0b5900e93 100644 --- a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseTable.cs +++ b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseTable.cs @@ -14,6 +14,11 @@ namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata /// public class DatabaseTable : Annotatable { + /// + /// Creates a new instance of the class. + /// + /// The database containing this table. + /// The name of the table. public DatabaseTable([NotNull] DatabaseModel database, [NotNull] string name) { Database = database; @@ -69,6 +74,7 @@ public DatabaseTable([NotNull] DatabaseModel database, [NotNull] string name) /// public virtual IList ForeignKeys { get; } + /// public override string ToString() => Schema == null ? Name : $"{Schema}.{Name}"; } } diff --git a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseUniqueConstraint.cs b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseUniqueConstraint.cs index 7f24cc62a4a..36c052cb3f0 100644 --- a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseUniqueConstraint.cs +++ b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseUniqueConstraint.cs @@ -14,6 +14,11 @@ namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata /// public class DatabaseUniqueConstraint : Annotatable { + /// + /// Creates a new instance of the class. + /// + /// The table containing this unique constraint. + /// The name of the unique constraint. public DatabaseUniqueConstraint([NotNull] DatabaseTable table, [CanBeNull] string? name) { Table = table; @@ -36,6 +41,7 @@ public DatabaseUniqueConstraint([NotNull] DatabaseTable table, [CanBeNull] strin /// public virtual IList Columns { get; } + /// public override string ToString() => Name ?? ""; } } diff --git a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseView.cs b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseView.cs index 1723bd37cf2..d66b53b8660 100644 --- a/src/EFCore.Relational/Scaffolding/Metadata/DatabaseView.cs +++ b/src/EFCore.Relational/Scaffolding/Metadata/DatabaseView.cs @@ -12,6 +12,11 @@ namespace Microsoft.EntityFrameworkCore.Scaffolding.Metadata /// public class DatabaseView : DatabaseTable { + /// + /// Creates a new instance of the class. + /// + /// The database containing this view. + /// The name of the view. public DatabaseView([NotNull] DatabaseModel database, [NotNull] string name) : base(database, name) { diff --git a/src/EFCore.Relational/Storage/ReaderColumn.cs b/src/EFCore.Relational/Storage/ReaderColumn.cs index 15136a143cb..cb9a2f9ef9a 100644 --- a/src/EFCore.Relational/Storage/ReaderColumn.cs +++ b/src/EFCore.Relational/Storage/ReaderColumn.cs @@ -22,6 +22,12 @@ public abstract class ReaderColumn private static readonly ConcurrentDictionary _constructors = new ConcurrentDictionary(); + /// + /// Creates a new instance of the class. + /// + /// The CLR type of the column. + /// A value indicating if the column is nullable. + /// The name of the column. protected ReaderColumn([NotNull] Type type, bool nullable, [CanBeNull] string name) { Type = type; @@ -29,8 +35,17 @@ protected ReaderColumn([NotNull] Type type, bool nullable, [CanBeNull] string na Name = name; } + /// + /// The CLR type of the column. + /// public virtual Type Type { get; } + /// + /// A value indicating if the column is nullable. + /// public virtual bool IsNullable { get; } + /// + /// The name of the column. + /// public virtual string Name { get; } /// diff --git a/src/EFCore.Relational/Storage/ReaderColumn`.cs b/src/EFCore.Relational/Storage/ReaderColumn`.cs index bbb0e47f5f0..7bfc8a8b1ff 100644 --- a/src/EFCore.Relational/Storage/ReaderColumn`.cs +++ b/src/EFCore.Relational/Storage/ReaderColumn`.cs @@ -18,12 +18,21 @@ namespace Microsoft.EntityFrameworkCore.Storage /// public class ReaderColumn : ReaderColumn { + /// + /// Creates a new instance of the class. + /// + /// A value indicating if the column is nullable. + /// The name of the column. + /// A function to get field value for the column from the reader. public ReaderColumn(bool nullable, [CanBeNull] string name, [NotNull] Func getFieldValue) : base(typeof(T), nullable, name) { GetFieldValue = getFieldValue; } + /// + /// The function to get field value for the column from the reader. + /// public virtual Func GetFieldValue { get; } } } diff --git a/src/EFCore.Relational/Update/ColumnModification.cs b/src/EFCore.Relational/Update/ColumnModification.cs index 8ebd6ab8b29..bdb0e9c3dbd 100644 --- a/src/EFCore.Relational/Update/ColumnModification.cs +++ b/src/EFCore.Relational/Update/ColumnModification.cs @@ -210,11 +210,14 @@ public ColumnModification( /// public virtual bool IsCondition { get; } + /// + /// Indicates whether or not the column is concurrency token. + /// [Obsolete] public virtual bool IsConcurrencyToken { get; } /// - /// Indicates whether or not the column part of a primary or alternate key. + /// Indicates whether or not the column is part of a primary or alternate key. /// public virtual bool IsKey { get; } diff --git a/src/EFCore/Infrastructure/CoreOptionsExtension.cs b/src/EFCore/Infrastructure/CoreOptionsExtension.cs index 82b1da8642f..2f80ef6cd50 100644 --- a/src/EFCore/Infrastructure/CoreOptionsExtension.cs +++ b/src/EFCore/Infrastructure/CoreOptionsExtension.cs @@ -383,14 +383,15 @@ public virtual CoreOptionsExtension WithInterceptors([NotNull] IEnumerable /// The option set from the /// + /// cref="EntityFrameworkServiceCollectionExtensions.AddDbContextPool{TContext}(IServiceCollection,Action{DbContextOptionsBuilder},int)" /> /// method. /// public virtual int? MaxPoolSize => _maxPoolSize; -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + /// + /// The options set from the method. + /// public virtual IEnumerable Interceptors => _interceptors; -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Adds the services required to make the selected options work. This is used when there diff --git a/src/EFCore/Infrastructure/ExpressionExtensions.cs b/src/EFCore/Infrastructure/ExpressionExtensions.cs index 95492c715ba..13884200caf 100644 --- a/src/EFCore/Infrastructure/ExpressionExtensions.cs +++ b/src/EFCore/Infrastructure/ExpressionExtensions.cs @@ -12,7 +12,6 @@ using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; diff --git a/src/EFCore/Infrastructure/ProductInfo.cs b/src/EFCore/Infrastructure/ProductInfo.cs index 7903b00d11e..ecbad7949a8 100644 --- a/src/EFCore/Infrastructure/ProductInfo.cs +++ b/src/EFCore/Infrastructure/ProductInfo.cs @@ -5,14 +5,12 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure { -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member See issue#20837 public static class ProductInfo -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member { -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static string GetVersion() -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member => typeof(ProductInfo).Assembly .GetCustomAttribute().InformationalVersion; } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member } diff --git a/src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs b/src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs index 524f78164f3..b1da72b721e 100644 --- a/src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs +++ b/src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs @@ -5,9 +5,16 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Builders { -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + /// + /// + /// Provides a simple API surface for configuring an from conventions. + /// + /// + /// This interface is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// public interface IConventionNavigationBuilder : IConventionAnnotatableBuilder -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member { /// /// Gets the navigation being configured. diff --git a/src/EFCore/Metadata/MemberIdentity.cs b/src/EFCore/Metadata/MemberIdentity.cs index 34644602c42..48e6a0481de 100644 --- a/src/EFCore/Metadata/MemberIdentity.cs +++ b/src/EFCore/Metadata/MemberIdentity.cs @@ -16,7 +16,7 @@ public readonly struct MemberIdentity private readonly object _nameOrMember; [DebuggerStepThrough] -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member See issue#20837 public MemberIdentity([NotNull] string name) : this((object)name) { diff --git a/src/EFCore/Query/QueryContext.cs b/src/EFCore/Query/QueryContext.cs index 60380aa0fe1..239241f8ce1 100644 --- a/src/EFCore/Query/QueryContext.cs +++ b/src/EFCore/Query/QueryContext.cs @@ -17,7 +17,13 @@ namespace Microsoft.EntityFrameworkCore.Query { /// - /// The principal data structure used by a compiled query during execution. + /// + /// The principal data structure used by a compiled query during execution. + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// /// public abstract class QueryContext : IParameterValues { diff --git a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CustomPartitionKeyIdGenerator.cs b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CustomPartitionKeyIdGenerator.cs index 17c6ffae9a8..9468325d0a1 100644 --- a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CustomPartitionKeyIdGenerator.cs +++ b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CustomPartitionKeyIdGenerator.cs @@ -29,7 +29,7 @@ protected override object NextValue(EntityEntry entry) AppendString(builder, discriminator); builder.Append("-"); } - + var partitionKey = entityType.GetPartitionKeyPropertyName() ?? CosmosClientWrapper.DefaultPartitionKey; foreach (var property in pk.Properties.Where(p => p.Name != StoreKeyConvention.IdPropertyName)) { @@ -45,7 +45,7 @@ protected override object NextValue(EntityEntry entry) { value = converter.ConvertToProvider(value); } - + if (value is int x) { // We don't allow the Id to be zero for our custom generator. diff --git a/test/EFCore.Relational.Tests/Metadata/Conventions/Internal/QueryableDbFunctionConventionTest.cs b/test/EFCore.Relational.Tests/Metadata/Conventions/Internal/TableValuedDbFunctionConventionTest.cs similarity index 89% rename from test/EFCore.Relational.Tests/Metadata/Conventions/Internal/QueryableDbFunctionConventionTest.cs rename to test/EFCore.Relational.Tests/Metadata/Conventions/Internal/TableValuedDbFunctionConventionTest.cs index f21590e99ab..19ecd87fcb3 100644 --- a/test/EFCore.Relational.Tests/Metadata/Conventions/Internal/QueryableDbFunctionConventionTest.cs +++ b/test/EFCore.Relational.Tests/Metadata/Conventions/Internal/TableValuedDbFunctionConventionTest.cs @@ -13,13 +13,13 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal { - public class QueryableDbFunctionConventionTest + public class TableValuedDbFunctionConventionTest { [ConditionalFact] public void Configures_return_entity_as_not_mapped_keyless() { var modelBuilder = CreateModelBuilder(); - modelBuilder.HasDbFunction(typeof(QueryableDbFunctionConventionTest).GetMethod( + modelBuilder.HasDbFunction(typeof(TableValuedDbFunctionConventionTest).GetMethod( nameof(GetKeylessEntities), BindingFlags.NonPublic | BindingFlags.Static)); @@ -36,7 +36,7 @@ public void Finds_existing_entity_type() { var modelBuilder = CreateModelBuilder(); modelBuilder.Entity().ToTable("TestTable").HasKey(e => e.Name); - modelBuilder.HasDbFunction(typeof(QueryableDbFunctionConventionTest).GetMethod( + modelBuilder.HasDbFunction(typeof(TableValuedDbFunctionConventionTest).GetMethod( nameof(GetEntities), BindingFlags.NonPublic | BindingFlags.Static)); @@ -53,7 +53,7 @@ public void Throws_when_adding_a_function_returning_an_owned_type() { var modelBuilder = CreateModelBuilder(); modelBuilder.Owned(); - modelBuilder.HasDbFunction(typeof(QueryableDbFunctionConventionTest).GetMethod( + modelBuilder.HasDbFunction(typeof(TableValuedDbFunctionConventionTest).GetMethod( nameof(GetKeylessEntities), BindingFlags.NonPublic | BindingFlags.Static)); @@ -68,7 +68,7 @@ public void Throws_when_adding_a_function_returning_an_existing_owned_type() { var modelBuilder = CreateModelBuilder(); modelBuilder.Entity().OwnsOne(e => e.KeylessEntity); - modelBuilder.HasDbFunction(typeof(QueryableDbFunctionConventionTest).GetMethod( + modelBuilder.HasDbFunction(typeof(TableValuedDbFunctionConventionTest).GetMethod( nameof(GetKeylessEntities), BindingFlags.NonPublic | BindingFlags.Static)); @@ -82,7 +82,7 @@ public void Throws_when_adding_a_function_returning_an_existing_owned_type() public void Throws_when_adding_a_function_returning_a_scalar() { var modelBuilder = CreateModelBuilder(); - modelBuilder.HasDbFunction(typeof(QueryableDbFunctionConventionTest).GetMethod( + modelBuilder.HasDbFunction(typeof(TableValuedDbFunctionConventionTest).GetMethod( nameof(GetScalars), BindingFlags.NonPublic | BindingFlags.Static)); diff --git a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs index f111dfde8df..a63d216535c 100644 --- a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs +++ b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs @@ -8574,7 +8574,7 @@ private static IQueryable GetCountByYear(int id) => throw new NotImplementedException(); [ConditionalFact] - public void Model_differ_does_not_detect_queryable_function_result_type() + public void Model_differ_does_not_detect_table_valued_function_result_type() { Execute( _ => { },