Как создать последовательный уникальный номер в зависимости от типа приложения - PullRequest
0 голосов
/ 11 июня 2018

Я создал веб-приложение MVC и должен генерировать уникальный последовательный серийный номер по типу приложения и году, когда пользователи отправляют форму.

Серийный номер будет сохранен в таблице базы данных MyAppCodeSEQ истолбец "AppCode" является PK MyAppCodeSEQ.

Это мой код ниже:

public MyAppCodeSEQ GenNewAppCode(string appType)
{
    MyAppCodeSEQ model = null;
    try
    {
        var today = DateTime.Now;

        int maxSeq = _db.MyAppCodeSEQ.Where(x => x.AppType == appType && x.Year == today.Year).Select(x => x.SEQ).DefaultIfEmpty(0).Max();

        maxSeq = maxSeq + 1;
        var appCode = "XX" + appType + today.Year % 1000 + string.Format("{0:000000}", maxSeq);

        model = new MyAppCodeSEQ()
        {
            AppCode = appCode,
            AppType = appType,
            Year = today.Year,
            SEQ = maxSeq,                        
        };

        _db.MyAppCodeSEQ.Add(model);
        _db.SaveChanges();             
    }
    catch(Exception e)
    {      
        Thread.Sleep(100);
        GenNewAppCode(appType);
    }

    return model;
}

Функция будет вызываться при вставке дублированного ключа.Тем не менее, ошибка ниже возникала снова и снова.

System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. 
---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. 
---> System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK_AppCodeSEQ'. 
Cannot insert duplicate key in object 'dbo.MyAppCodeSEQ'. The duplicate key value is (XXYY18002193).
The statement has been terminated.
 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
 System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
 System.Data.SqlClient.SqlDataReader.get_MetaData()
 System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption)
 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
 System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
 System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
 System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
 System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.Execute(Dictionary`2 identifierValues, List`1 generatedValues)
 System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
 System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
 System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
 System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
 System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
 System.Data.Entity.Internal.InternalContext.SaveChanges()

Есть ли лучшее решение для создания серийного номера?

1 Ответ

0 голосов
/ 11 июня 2018

а) НИКОГДА не иметь первичного ключа, который можно редактировать, пусть база данных сгенерирует первичный ключ

б) Поля, о которых вы говорите, являются ключом-кандидатом, а целью обычно является "сортировка"в последовательность по умолчанию или для обеспечения уникальности

c) Последовательный ключ - это практически бессмысленная часть данных

Тем не менее, есть одна возможность:

Изменить ваш класс (MyAppCodeSEQ), чтобы включить поле Добавлено как DateTime.Уникальный индекс на AppCode, AppType, Year для предотвращения дублирования.Индекс по AppCode, AppType, Year, Добавлено для сохранения последовательности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...