locked
The changes to the database were committed successfully, but an error occurred while updating the object context RRS feed

  • Question

  • User-1104215994 posted

    Hi,

    I have <g class="gr_ gr_10 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar multiReplace" id="10" data-gr-id="10">a asp.net</g> web API. I am using EF 6 code first approach. I am getting this error only when I load testing my web API with Jmeter. How can I fix this?

    The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: Saving or accepting changes failed because more than one entity of type 'BusinessEntity.GameResponse' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.

    Here is my GameResponse:

    using System;
    
    namespace BusinessEntity
    {
        public class GameResponse
        {
            public int Id { get; set; }
            public string referenceId { get; set; }
            public string productCode { get; set; }
            public int quantity { get; set; }
            public string version { get; set; }
            public string signature { get; set; }
            public string ApplicationCode { get; set; }
            public string validatedToken { get; set; }
            public DateTime? responseDateTime { get; set; } = DateTime.Now;
            public string initiationResultCode { get; set; }
            public string companyToken { get; set; }
            public string estimateUnitPrice { get; set; }
            public string currency { get; set; }
        }
    }
    

    Here is the method I am load testing:

    private async Task<HttpResponseMessage> CallRazerService(RequestDto requestDto)
            {
                HttpResponseMessage response = null;
    
                using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
                {
                    try
                    {
                        //Transform DTO into GameRequest for calling Razer Initiate
                        var config = new MapperConfiguration(cfg =>
                        {
                            cfg.CreateMap<RequestDto, GameRequest>();
                            cfg.CreateMap<GameRequest, GameConfirmRequest>();
                            cfg.CreateMap<GameConfirmResponse, GameConfirmResponseDto>();
                            cfg.CreateMap<Coupon, CouponDto>();
                        });
                        var iMapper = config.CreateMapper();
                        var gameRequest = iMapper.Map<RequestDto, GameRequest>(requestDto);
                        //Unique reference ID
                        gameRequest.referenceId = Guid.NewGuid().ToString();
    
                        //Create signature
                        gameRequest = Utilities.CreateSignature(gameRequest, RequestType.Initiate);
    
                        //Add initiation request into database
                        _unitOfWork.GameRepository.Insert(gameRequest);
                        
    
                        #region Call Razer initiate/confirm
    
                        //Call Razer for initiation
                        response = await Utilities.CallRazer(gameRequest, "purchaseinitiation");
    
                        //Read response
                        var htmlResponse = await response.Content.ReadAsStringAsync();
                        var gameResponse = JsonConvert.DeserializeObject<GameResponse>(htmlResponse);
    
                        //Adding initiation response into database
                        _unitOfWork.GameResponseRepository.Insert(gameResponse);
                        
    
                        if (gameResponse.initiationResultCode == "00")
                        {
                            gameRequest.validatedToken = gameResponse.validatedToken;
                            //Create signature
                            var gameConfirmRequest = Utilities.CreateSignature(gameRequest, RequestType.Confirm);
    
                            //Transform DTO into GameRequest for calling Razer Initiate
                            var gameConfirmRequests = iMapper.Map<GameRequest, GameConfirmRequest>(gameConfirmRequest);
    
                            //Add confirm request into database
                            _unitOfWork.GameConfirmRequestRepository.Insert(gameConfirmRequests);
                            
    
                            //Call Razer for confirm
                            response = await Utilities.CallRazer(gameRequest, "purchaseconfirmation");
    
                            //Read response
                            htmlResponse = await response.Content.ReadAsStringAsync();
                            var gameConfirmResponse = JsonConvert.DeserializeObject<GameConfirmResponse>(htmlResponse);
    
                            //Add confirm response into database
                            _unitOfWork.GameConfirmResponseRepository.Insert(gameConfirmResponse);
                        }
                    }
                    catch (Exception e)
                    {
                        throw e;
                    }
    
                    #endregion
    
                    await _unitOfWork.SaveAsync();
                    scope.Complete();
                }
    
                return response;
            }

    Saturday, July 20, 2019 10:50 AM

Answers

  • User-1104215994 posted

    Changed my business logic, now everything work just I want.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, July 28, 2019 6:19 PM

All replies

  • User475983607 posted

    The error points to a design bug probably the same design bug in mentioned in your recent threads.  I suspect the DbContext is leaking outside the current context and the bug is in the IoC configuration.  It can also be due to the UoW or Generic Repository design.

    It's also possible that the primary key design does not allow asynchronous or a delayed INSERT.  Thread access to create a new records must be serialized.  This can happen if the primary key is not a GUID and assigned by code running on the web server.

    IMHO, simplifying the design will solve these issues. 

    Saturday, July 20, 2019 12:49 PM
  • User753101303 posted

    Hi,

    Keep using the same thread until solved. For now it seems you are using a single context for the whole app which is likely the root cause for all your current issues (or you changed this ?)

    Sunday, July 21, 2019 9:31 AM
  • User-1104215994 posted

    I have only one Dbcontext for the app. I changed <g class="gr_ gr_31 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar only-ins replaceWithoutSep" id="31" data-gr-id="31">couple</g> of things. First of <g class="gr_ gr_32 gr-alert gr_gramm gr_inline_cards gr_run_anim Punctuation only-ins replaceWithoutSep" id="32" data-gr-id="32">all</g> I was setting <g class="gr_ gr_25 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="25" data-gr-id="25">referenceId</g> which is a unique <g class="gr_ gr_26 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="26" data-gr-id="26">guid</g> manually. Then adding an entity with this <g class="gr_ gr_27 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="27" data-gr-id="27">referenceId</g>. After <g class="gr_ gr_33 gr-alert gr_gramm gr_inline_cards gr_run_anim Punctuation only-ins replaceWithoutSep" id="33" data-gr-id="33">that</g> I am using this same <g class="gr_ gr_28 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="28" data-gr-id="28">referenceId</g> in another entity to add into <g class="gr_ gr_30 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar only-ins doubleReplace replaceWithoutSep" id="30" data-gr-id="30">database</g>.

    Now SQL server generates <g class="gr_ gr_18 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="18" data-gr-id="18">referenceId</g> for me as follows:

    public class GameRequest
        {
            public int Id { get; set; }
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public Guid referenceId { get; set; }
    ...

    Here is my code now. But <g class="gr_ gr_19 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar only-ins replaceWithoutSep" id="19" data-gr-id="19">problem</g> is how can I get the generated <g class="gr_ gr_21 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="21" data-gr-id="21">refenerceId</g> when I insert it into <g class="gr_ gr_20 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar only-ins doubleReplace replaceWithoutSep" id="20" data-gr-id="20">database</g>. AFAIK, after SaveAsync insertion is made. Somehow I need to use this SQL generated <g class="gr_ gr_22 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="22" data-gr-id="22">referenceId</g> in order to use it call Razer for <g class="gr_ gr_23 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar multiReplace" id="23" data-gr-id="23">confirm</g>. (see <g class="gr_ gr_50 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="50" data-gr-id="50">gameRequest</g> in the code below)

    Forgot to mention that, I am getting this error when I changed the <g class="gr_ gr_16 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="16" data-gr-id="16">referenceIdto</g> <g class="gr_ gr_17 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="17" data-gr-id="17">Guid</g>.

    System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'GameRequests' when IDENTITY_INSERT is set to OFF.

    ... 
    var config = new MapperConfiguration(cfg => { cfg.CreateMap<RequestDto, GameRequest>(); cfg.CreateMap<GameRequest, GameConfirmRequest>(); cfg.CreateMap<GameConfirmResponse, GameConfirmResponseDto>(); cfg.CreateMap<Coupon, CouponDto>(); cfg.CreateMap<GameRequest, GameRequestDto>(); }); var iMapper = config.CreateMapper(); var gameRequest = iMapper.Map<RequestDto, GameRequest>(requestDto); //Unique reference ID //gameRequest.referenceId = Guid.NewGuid().ToString(); var gameRequestDto = iMapper.Map<GameRequest, GameRequestDto>(gameRequest); //Create signature gameRequest = Utilities.CreateSignature(gameRequestDto, RequestType.Initiate); //Add initiation request into database _unitOfWork.GameRepository.Insert(gameRequest); #region Call Razer initiate/confirm //Call Razer for initiation response = await Utilities.CallRazer(gameRequest, "purchaseinitiation"); //Read response var htmlResponse = await response.Content.ReadAsStringAsync(); var gameResponse = JsonConvert.DeserializeObject<GameResponse>(htmlResponse); //Adding initiation response into database _unitOfWork.GameResponseRepository.Insert(gameResponse); if (gameResponse.initiationResultCode == "00") { gameRequestDto = iMapper.Map<GameRequest, GameRequestDto>(gameRequest); gameRequestDto.validatedToken = gameResponse.validatedToken; //Create signature var gameConfirmRequest = Utilities.CreateSignature(gameRequestDto, RequestType.Confirm); //Transform DTO into GameRequest for calling Razer Initiate var gameConfirmRequests = iMapper.Map<GameRequest, GameConfirmRequest>(gameConfirmRequest); //Add confirm request into database _unitOfWork.GameConfirmRequestRepository.Insert(gameConfirmRequests); //Call Razer for confirm response = await Utilities.CallRazer(gameRequest, "purchaseconfirmation");
    ...

    await _unitOfWork.SaveAsync();
    Sunday, July 21, 2019 2:11 PM
  • User-1104215994 posted

    Changed my business logic, now everything work just I want.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, July 28, 2019 6:19 PM