1

Good afternoon,

I have an error, and I think you can help me.

  • Error
System.InvalidOperationException
HResult=0x80131509
Message=Attaching an entity of type 'SGI2DataAccess.Models.ProjectForecast' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
Source=EntityFramework
StackTrace:
at System.Data.Entity.Core.Objects.ObjectContext.VerifyRootForAdd(Boolean doAttach, String entitySetName, IEntityWrapper wrappedEntity, EntityEntry existingEntry, EntitySet& entitySet, Boolean& isNoOperation)
at System.Data.Entity.Core.Objects.ObjectContext.AttachTo(String entitySetName, Object entity)
at System.Data.Entity.Internal.Linq.InternalSet`1.<>c__DisplayClassa.<Attach>b__9()
at System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)
at System.Data.Entity.Internal.Linq.InternalSet`1.Attach(Object entity)
at System.Data.Entity.DbSet`1.Attach(TEntity entity)
at SGI2.Data.Infrastructure.RepositoryBase`1.Update(T entity) in C:\work\sgi\SGI2.Data\Infrastructure\RepositoryBase.cs:line 41
at SGI2.Service.Services.Projects.ForecastProject.UpdateForecast(List`1 forecasts, ProjetoVM Projeto) in C:\work\sgi\SGI2.Service\Services\Projects\ForecastProject.cs:line 79
at SGI2.Service.ProjetosService.UpdateProjeto(ProjetoEditVM VM, Int32 userId, String userNomeConhecido) in C:\work\sgi\SGI2.Service\Services\Projects\ProjetosService.cs:line 1212
at SGI2.Controllers.ProjetosController.Edit(ProjetoEditVM VM, String Command) in C:\work\sgi\SGI2\SGI2\Controllers\Projeto\ProjetosController.cs:line 312
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
  • Code object: \sgi2\SGI2\Controllers\Projeto\ProjetosController.cs
(...)
// Interface
private readonly IProjetosService _service;
(...)

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(ProjetoEditVM VM, string Command)
    {
        #region PERMISSOES
        if (!ClaimsAuthorization.CheckAccess("generic-editprojetos", VM.Projeto.Id.ToString(), VM.Projeto.EstadoId.ToString()))
            return new HttpStatusCodeResult(HttpStatusCode.Forbidden);

        // Completed projects should never be able to be edited
        if (_service.GetProjeto(VM.Projeto.Id).EstadoId == 2)
            return new HttpStatusCodeResult(HttpStatusCode.Forbidden);

        #endregion
        else if (ModelState.IsValid)
        {
            if (VM.Projeto.EstadoId == 2 && (VM.Projeto.TipoId == 8 || VM.Projeto.TipoId == 9) && !_service.GetAllProjetosPPRInfo(x => x.ProjetoId == VM.Projeto.Id && x.IsTheLast).Any())
            {
                return RedirectToAction("Edit", new { Id = VM.Projeto.Id, param = "CloseProjectLastPPRInfoError" });
            }


            // Se vem do botão "Refresh Forecast", atualizar valores, antes de submeter com valores desatualizados
            if (Command == "RefreshForecastButton")
            {
                _service.UpdateProjetoRF(VM, UserId, UserNomeConhecido); // ok
                RefreshForecastButton(VM, Command, UserId, UserNomeConhecido);
                _service.UpdateProjeto(VM, UserId, UserNomeConhecido); // NOT ok
            }
            (...) 
        }  (...) 

    }
(...)

object: \sgi\SGI2.Service\Services\Projects\ProjetosService.cs

public void UpdateProjeto(ProjetoEditVM VM, int userId, string userNomeConhecido)
{
    //Atualiza projeto

    var dbObj = projetosRepository.GetById(VM.Projeto.Id);
    (...)
    new ForecastProject(projectForecastRepository, projetoPPRInfoRepository).UpdateForecast(VM.Forecasts, VM.Projeto);
    (...)
    unitOfWork.Commit();

}

object: \sgi\SGI2.Service\Services\Projects\ForecastProject.cs

namespace SGI2.Service.Services.Projects
{ 
    //Tenho de criar uma interface e remover a dependecia dos repositórios
    public class ForecastProject
    {  
       
        private readonly IProjectForecastRepository projectForecastRepository;
        private readonly IProjetoPPRInfoRepository projetoPPRInfoRepository;
        private readonly IForecastDomain Iforecast = new ForecastDomain();


        public ForecastProject(IProjectForecastRepository projectForecastRepository, IProjetoPPRInfoRepository projetoPPRInfoRepository)
        {
            this.projectForecastRepository = projectForecastRepository;
            this.projetoPPRInfoRepository = projetoPPRInfoRepository;
        }
        (...)
        
        public void UpdateForecast(List<ProjectForecastEditVM> forecasts, ProjetoVM Projeto)
        {
            // 1º Caso não exista linhas
            if (forecasts == null || forecasts.Count() == 0)
            {
                foreach (var item in Iforecast.InitialLinesForecast(Projeto))
                {
                    projectForecastRepository.Add(item);
                }
            }

            // 2º caso a data de fim do projeto aumente
            else if (Projeto.RealEndDate > forecasts.LastOrDefault().EndDate)
            {
                foreach (var item in Iforecast.ChangeRealEndDateForecast(Projeto,forecasts.LastOrDefault().EndDate))
                {
                    projectForecastRepository.Add(item);
                }
            }

            else
            {
                List<ProjectForecast> Forecasts = new List<ProjectForecast>();
                foreach (var i in forecasts)
                {
                    //Está assim pois a data fim pode mudar e deixar de ser o ultimo dia do mês
                    DateTime EndDate = new DateTime(i.EndDate.Year, i.EndDate.Month, DateTime.DaysInMonth(i.EndDate.Year, i.EndDate.Month));
                    //Ultimo dia do mês do projeto
                    DateTime LastDateofProject = new DateTime(Projeto.RealEndDate.Value.Year, Projeto.RealEndDate.Value.Month, DateTime.DaysInMonth(Projeto.RealEndDate.Value.Year, Projeto.RealEndDate.Value.Month));

                    if (EndDate > LastDateofProject && i.CanWrite == true)
                    {
                        projectForecastRepository.Delete(projectForecastRepository.GetById(i.Id));
                    }
                    else
                    {
                        Forecasts.Add(UpdateForecastForecastFactory(Projeto, i));
                    }
                }

                foreach (var item in Forecasts)
                {
                    projectForecastRepository.Update(item); ! The error is thrown here !
                }
            }
        }
        
    }
}

object: \SGI2.Data\Infrastructure\IRepository.cs

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace SGI2.Data.Infrastructure
{
    public interface IRepository<T> where T : class
    {
        // Marks an entity as new
        void Add(T entity);
        // Marks an entity as modified
        void Update(T entity);
        // Marks an entity to be removed
        void Delete(T entity);
        void Delete(Expression<Func<T, bool>> where);
        // Get an entity by int id
        T GetById(int id);
        // Get an entity using delegate
        T Get(Expression<Func<T, bool>> where);
        // Gets all entities of type T
        IEnumerable<T> GetAll();
        // Gets entities using delegate
        IEnumerable<T> GetMany(Expression<Func<T, bool>> where);


    }
}

object: \SGI2.Data\Infrastructure\RepositoryBase.cs

public virtual void Update(T entity)
{
    dbSet.Attach(entity); ! The error is thrown here !
    dataContext.Entry(entity).State = EntityState.Modified;
}

What can I do to resolve? What i want is call twice :_service.UpdateProjeto

Best regards Isabel Fonseca

  • 1
    You seem to be using a factory to create new (updated??) items. Do you make sure they have the correct keys? Or Keys at all? If they don't have any, you cannot update them. If they have, then you may need to *de*tach from the former instance with the same id first. – Fildor Feb 22 '23 at 17:08
  • Does [this](https://stackoverflow.com/questions/30987806/dbset-attachentity-vs-dbcontext-entryentity-state-entitystate-modified) answer your question? – Serg Feb 22 '23 at 17:09
  • The situation was resolved. public virtual void Update(T entity, int id) { var aExists = dbSet.Find(id); if (aExists == null) { dbSet.Add(entity); } else { dataContext.Entry(aExists).State = EntityState.Detached; dbSet.Attach(entity); dataContext.Entry(entity).State = EntityState.Modified; } }Thanks. – Isabel Fonseca Feb 23 '23 at 11:40

0 Answers0