/// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public override void AddDbParameter(DbCommand command, object value)
        {
            Check.NotNull(command, nameof(command));

            if (value == null)
            {
                command.Parameters
                .Add(
                    _typeMapper.GetMappingForValue(null)
                    .CreateParameter(command, Name, null));

                return;
            }

            if (value is DbParameter dbParameter)
            {
                command.Parameters.Add(dbParameter);

                return;
            }

            var type = value.GetType();

            command.Parameters.Add(
                _typeMapper.GetMapping(type)
                .CreateParameter(command, Name, value, type.IsNullableType()));
        }
        /// <summary>
        ///     Creates a new <see cref="TypeMaterializationInfo" /> instance.
        /// </summary>
        /// <param name="modelType"> The type that is needed in the model after conversion. </param>
        /// <param name="property"> The property associated with the type, or <c>null</c> if none. </param>
        /// <param name="typeMapper"> The type mapper to use to find a mapping if the property does not have one already bound. </param>
        /// <param name="index">
        ///     The index of the underlying result set that should be used for this type,
        ///     or -1 if no index mapping is needed.
        /// </param>
        public TypeMaterializationInfo(
            [NotNull] Type modelType,
            [CanBeNull] IProperty property,
            [CanBeNull] IRelationalCoreTypeMapper typeMapper,
            int index = -1)
        {
            Check.NotNull(modelType, nameof(modelType));

            var mapping = property?.FindRelationalMapping()
                          ?? typeMapper?.GetMapping(modelType);

            StoreType = mapping?.Converter?.StoreType
                        ?? modelType.UnwrapNullableType().UnwrapEnumType();

            ModelType = modelType;
            Mapping   = mapping;
            Property  = property;
            Index     = index;
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual TypeScaffoldingInfo FindMapping(
            string storeType,
            bool keyOrIndex,
            bool rowVersion)
        {
            // This is because certain providers can have no type specified as a default type e.g. SQLite
            Check.NotNull(storeType, nameof(storeType));

            var mapping = _typeMapper.FindMapping(storeType);
            if (mapping == null)
            {
                return null;
            }

            var canInfer = false;
            bool? scaffoldUnicode = null;
            int? scaffoldMaxLength = null;

            if (mapping.ClrType == typeof(byte[]))
            {
                // Check for inference
                var byteArrayMapping = _typeMapper.FindMapping(
                    typeof(byte[]),
                    keyOrIndex,
                    rowVersion: rowVersion,
                    size: mapping.Size);

                if (byteArrayMapping.StoreType.Equals(storeType, StringComparison.OrdinalIgnoreCase))
                {
                    canInfer = true;

                    // Check for size
                    var sizedMapping = _typeMapper.FindMapping(
                        typeof(byte[]),
                        keyOrIndex,
                        rowVersion: rowVersion);

                    scaffoldMaxLength = sizedMapping.Size != byteArrayMapping.Size ? byteArrayMapping.Size : null;
                }
            }
            else if (mapping.ClrType == typeof(string))
            {
                // Check for inference
                var stringMapping = _typeMapper.FindMapping(
                    typeof(string),
                    keyOrIndex,
                    unicode: mapping.IsUnicode,
                    size: mapping.Size);

                if (stringMapping.StoreType.Equals(storeType, StringComparison.OrdinalIgnoreCase))
                {
                    canInfer = true;

                    // Check for unicode
                    var unicodeMapping = _typeMapper.FindMapping(
                        typeof(string),
                        keyOrIndex,
                        unicode: true,
                        size: mapping.Size);

                    scaffoldUnicode = unicodeMapping.IsUnicode != stringMapping.IsUnicode ? (bool?)stringMapping.IsUnicode : null;

                    // Check for size
                    var sizedMapping = _typeMapper.FindMapping(
                        typeof(string),
                        keyOrIndex,
                        unicode: mapping.IsUnicode);

                    scaffoldMaxLength = sizedMapping.Size != stringMapping.Size ? stringMapping.Size : null;
                }
            }
            else
            {
                var defaultMapping = _typeMapper.GetMapping(mapping.ClrType);

                if (defaultMapping.StoreType.Equals(storeType, StringComparison.OrdinalIgnoreCase))
                {
                    canInfer = true;
                }
            }

            return new TypeScaffoldingInfo(
                mapping.ClrType,
                canInfer,
                scaffoldUnicode,
                scaffoldMaxLength);
        }