public override async Task ReindexInstanceAsync(DicomDataset instance, long watermark, IEnumerable <QueryTag> queryTags, CancellationToken cancellationToken = default)
        {
            EnsureArg.IsNotNull(instance, nameof(instance));
            EnsureArg.IsNotNull(queryTags, nameof(queryTags));

            using (SqlConnectionWrapper sqlConnectionWrapper = await SqlConnectionWrapperFactory.ObtainSqlConnectionWrapperAsync(cancellationToken))
                using (SqlCommandWrapper sqlCommandWrapper = sqlConnectionWrapper.CreateSqlCommand())
                {
                    var rows = ExtendedQueryTagDataRowsBuilder.Build(instance, queryTags, Version);
                    VLatest.IndexInstanceV2TableValuedParameters parameters = new VLatest.IndexInstanceV2TableValuedParameters(
                        rows.StringRows,
                        rows.LongRows,
                        rows.DoubleRows,
                        rows.DateTimeWithUtcRows,
                        rows.PersonNameRows);

                    VLatest.IndexInstanceV2.PopulateCommand(sqlCommandWrapper, watermark, parameters);

                    try
                    {
                        await sqlCommandWrapper.ExecuteNonQueryAsync(cancellationToken);
                    }
                    catch (SqlException ex)
                    {
                        throw ex.Number switch
                              {
                                  SqlErrorCodes.NotFound => new InstanceNotFoundException(),
                                  SqlErrorCodes.Conflict => new PendingInstanceException(),
                                  _ => new DataStoreException(ex),
                              };
                    }
                }
        }
        public override async Task <long> BeginCreateInstanceIndexAsync(int partitionKey, DicomDataset instance, IEnumerable <QueryTag> queryTags, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(instance, nameof(instance));
            EnsureArg.IsNotNull(queryTags, nameof(queryTags));

            using (SqlConnectionWrapper sqlConnectionWrapper = await SqlConnectionWrapperFactory.ObtainSqlConnectionWrapperAsync(cancellationToken))
                using (SqlCommandWrapper sqlCommandWrapper = sqlConnectionWrapper.CreateSqlCommand())
                {
                    var rows = ExtendedQueryTagDataRowsBuilder.Build(instance, queryTags.Where(tag => tag.IsExtendedQueryTag), Version);
                    VLatest.AddInstanceV6TableValuedParameters parameters = new VLatest.AddInstanceV6TableValuedParameters(
                        rows.StringRows,
                        rows.LongRows,
                        rows.DoubleRows,
                        rows.DateTimeWithUtcRows,
                        rows.PersonNameRows
                        );

                    VLatest.AddInstanceV6.PopulateCommand(
                        sqlCommandWrapper,
                        partitionKey,
                        instance.GetString(DicomTag.StudyInstanceUID),
                        instance.GetString(DicomTag.SeriesInstanceUID),
                        instance.GetString(DicomTag.SOPInstanceUID),
                        instance.GetSingleValueOrDefault <string>(DicomTag.PatientID),
                        instance.GetSingleValueOrDefault <string>(DicomTag.PatientName),
                        instance.GetSingleValueOrDefault <string>(DicomTag.ReferringPhysicianName),
                        instance.GetStringDateAsDate(DicomTag.StudyDate),
                        instance.GetSingleValueOrDefault <string>(DicomTag.StudyDescription),
                        instance.GetSingleValueOrDefault <string>(DicomTag.AccessionNumber),
                        instance.GetSingleValueOrDefault <string>(DicomTag.Modality),
                        instance.GetStringDateAsDate(DicomTag.PerformedProcedureStepStartDate),
                        instance.GetStringDateAsDate(DicomTag.PatientBirthDate),
                        instance.GetSingleValueOrDefault <string>(DicomTag.ManufacturerModelName),
                        (byte)IndexStatus.Creating,
                        parameters);

                    try
                    {
                        return((long)(await sqlCommandWrapper.ExecuteScalarAsync(cancellationToken)));
                    }
                    catch (SqlException ex)
                    {
                        if (ex.Number == SqlErrorCodes.Conflict)
                        {
                            if (ex.State == (byte)IndexStatus.Creating)
                            {
                                throw new PendingInstanceException();
                            }

                            throw new InstanceAlreadyExistsException();
                        }

                        throw new DataStoreException(ex);
                    }
                }
        }
        public void GivenSupportedDicomElement_WhenRead_ThenShouldReturnExpectedValue(DicomElement element, int schemaVersion, object expectedValue)
        {
            DicomDataset dataset = new DicomDataset();

            dataset.Add(element);
            QueryTag tag        = new QueryTag(element.Tag.BuildExtendedQueryTagStoreEntry(vr: element.ValueRepresentation.Code));
            var      parameters = ExtendedQueryTagDataRowsBuilder.Build(dataset, new QueryTag[] { tag }, (SchemaVersion)schemaVersion);

            ExtendedQueryTagDataType dataType = ExtendedQueryTagLimit.ExtendedQueryTagVRAndDataTypeMapping[element.ValueRepresentation.Code];

            switch (dataType)
            {
            case ExtendedQueryTagDataType.StringData:
                Assert.Equal(expectedValue, parameters.StringRows.First().TagValue);
                break;

            case ExtendedQueryTagDataType.LongData:
                Assert.Equal(expectedValue, parameters.LongRows.First().TagValue);
                break;

            case ExtendedQueryTagDataType.DoubleData:
                Assert.Equal(expectedValue, parameters.DoubleRows.First().TagValue);
                break;

            case ExtendedQueryTagDataType.DateTimeData:
                if (schemaVersion < SchemaVersionConstants.SupportDTAndTMInExtendedQueryTagSchemaVersion)
                {
                    Assert.Equal(expectedValue, parameters.DateTimeRows.First().TagValue);
                }
                else
                {
                    Assert.Equal(expectedValue, parameters.DateTimeWithUtcRows.First().TagValue);
                }
                break;

            case ExtendedQueryTagDataType.PersonNameData:
                Assert.Equal(expectedValue, parameters.PersonNameRows.First().TagValue);
                break;
            }
        }
        public override async Task EndCreateInstanceIndexAsync(
            int partitionKey,
            DicomDataset dicomDataset,
            long watermark,
            IEnumerable <QueryTag> queryTags,
            bool allowExpiredTags = false,
            CancellationToken cancellationToken = default)
        {
            EnsureArg.IsNotNull(dicomDataset, nameof(dicomDataset));
            EnsureArg.IsNotNull(queryTags, nameof(queryTags));

            using (SqlConnectionWrapper sqlConnectionWrapper = await SqlConnectionWrapperFactory.ObtainSqlConnectionWrapperAsync(cancellationToken))
                using (SqlCommandWrapper sqlCommandWrapper = sqlConnectionWrapper.CreateSqlCommand())
                {
                    VLatest.UpdateInstanceStatusV6.PopulateCommand(
                        sqlCommandWrapper,
                        partitionKey,
                        dicomDataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty),
                        dicomDataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty),
                        dicomDataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty),
                        watermark,
                        (byte)IndexStatus.Created,
                        allowExpiredTags ? null : ExtendedQueryTagDataRowsBuilder.GetMaxTagKey(queryTags));

                    try
                    {
                        await sqlCommandWrapper.ExecuteScalarAsync(cancellationToken);
                    }
                    catch (SqlException ex)
                    {
                        throw ex.Number switch
                              {
                                  SqlErrorCodes.NotFound => new InstanceNotFoundException(),
                                  SqlErrorCodes.Conflict when ex.State == 10 => new ExtendedQueryTagsOutOfDateException(),
                                  _ => new DataStoreException(ex),
                              };
                    }
                }
        }