Question

Object code :

public class ParticipatingService
{
    [Key]
    public int Id { get; set; }

    public int OptimisticVersion { get; set; }

    [DisplayName("Receiver site")]
    public int? TargetSiteId { get; set; }
    [DisplayName("Receiver site")]
    public virtual Hospital TargetSite { get; set; }

    [DisplayName("Provider site")]
    public int? SourceSiteId { get; set; }
    [DisplayName("Provider site")]
    public virtual Hospital SourceSite { get; set; }

    [DisplayName("Provider person")]
    public int? SourcePersonId { get; set; }
    [DisplayName("Provider person")]
    public virtual Person SourcePerson { get; set; }

    [DisplayName("Study")]
    public int StudyId { get; set; }
    [DisplayName("Study")]
    public virtual Study Study { get; set; }

    [DisplayName("Start date")]
    public virtual PartialDate StartDate { get; set; }
    [DisplayName("End date")]
    public virtual PartialDate EndDate { get; set; }

    public int? RegInvestigatorFormId { get; set; }
    public PartialDate AuthorizationDate { get; set; }
    public bool IsNationalCoordinator { get; set; }

    [DisplayName("Role")]
    public int RoleId { get; set; }
    [DisplayName("Role")]
    public virtual ParticipatingServiceCLI Role { get; set; }

    [DisplayName("Affiliation type")]
    public int? AffiliationId { get; set; }
    public virtual AffiliationCLI Affiliation { get; set; }

    public bool IsFromActivePersonSite
    {
        get
        {
            foreach (PersonSite personSite in SourcePerson.PersonSites.ToList().OrderByDescending(ps => ps.StartDate.Date))
            {
                if (personSite.SiteId == SourceSiteId)
                {
                    return personSite.IsActive();
                }
            }
            return false;
        }
    }

    public bool IsFromSecondarySite
    {
        get
        {
            foreach (PersonSite personSite in SourcePerson.PersonSites.ToList().OrderByDescending(ps => ps.StartDate.Date))
            {
                if (personSite.SiteId == SourceSiteId)
                {
                    return personSite.RelationType.StringId.Equals("Secondary");
                }
            }
            return false;
        }
    }

    public override bool IsActive()
    {
        return !this.IsDeleted && this.SourcePerson != null && this.Study != null && this.TargetSite != null && this.SourcePerson.IsActive() && this.TargetSite.IsActive() && (this.EndDate == null || this.EndDate.Date == null || this.EndDate.Date > DateTime.Now);
    }
}

Repository code :

public virtual T Update(T obj)
    {
        System.Data.Entity.Infrastructure.DbEntityEntry<T> dbEntry = this.Context.Entry<T>(obj);
        System.Data.Entity.Infrastructure.DbPropertyValues x = dbEntry.GetDatabaseValues();
        int optimisticValue = x.GetValue<int>("OptimisticVersion");
        if ((int)this.Context.Entry<T>(obj).GetDatabaseValues()["OptimisticVersion"] == obj.OptimisticVersion)
        {
            obj.OptimisticVersion++;
            obj.LastModificationDate = DateTime.Now;
            this.Context.Entry<T>(obj).State = EntityState.Modified;
            this.Context.SaveChanges();
            return obj;
        }
        throw new DBConcurrencyException("The selected item is obsolete !");
    }

The problem :

I'm using generic managers and generic repositories with CRUD operations (DRY). The problem is that when trying to save an object (only 1 type of the solution cause that problem), it works well the first time it is updated. Then trying to update the same object again cause a NullReferenceException on the GetDatabaseValues(). I've tried to split the following line :

(int)this.Context.Entry<T>(obj).GetDatabaseValues()["OptimisticVersion"] == obj.OptimisticVersion

into multiple lines :

System.Data.Entity.Infrastructure.DbEntityEntry<T> dbEntry = this.Context.Entry<T>(obj);
System.Data.Entity.Infrastructure.DbPropertyValues x = dbEntry.GetDatabaseValues();
int optimisticValue = x.GetValue<int>("OptimisticVersion");

Has anyone any idea why it can grab database values the first time and throw an exception on next calls ?

Here is the stack trace:

System.Data.Objects.EntityEntry.DetectChangesInComplexType(StateManagerMemberMetadata topLevelMember, StateManagerMemberMetadata complexMember, Object complexValue, Object oldComplexValue) 
at System.Data.Objects.EntityEntry.DetectChangesInProperties(Boolean detectOnlyComplexProperties) 
at System.Data.Objects.EntityEntry.InternalGetOriginalValues(Boolean readOnly) 
at System.Data.Objects.EntityEntry.GetUpdatableOriginalValues() 
at System.Data.Entity.Internal.StateEntryAdapter.GetUpdatableOriginalValues() 
at System.Data.Entity.Internal.InternalEntityEntry.get_OriginalValues() 
at System.Data.Entity.Internal.InternalEntityEntry.GetDatabaseValues() 
at System.Data.Entity.Infrastructure.DbEntityEntry`1.GetDatabaseValues() 
at EORTC.BASE.DAL.EORTCBaseRep`1.Update(T obj) in     C:\Projects\_Prisma\EORTC.BASE.DAL\EORTCBaseRep.cs:line 121 
at EORTC.BASE.BLL.EORTCBaseManager`1.Update(T obj, Boolean validate) in C:\Projects\_Prisma\EORTC.BASE.BLL\EORTCBaseManager.cs:line 58 
at Prisma.BLL.ParticipatingServiceManager.Update(ParticipatingService obj, Boolean validate) in C:\Projects\_Prisma\Prisma.BLL\Managers\Service\ParticipatingServiceManager.cs:line 96 
at Prisma.Web.Controllers.ParticipatingServiceController.Edit(Int32 id, FormCollection collection) in C:\Projects\_Prisma\Prisma.Web\Controllers\Service\ParticipatingServiceController.cs:line 172 
at lambda_method(Closure , ControllerBase , Object[] ) 
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.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() 
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) 
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() 
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) 
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) 
at System.Web.Mvc.Controller.ExecuteCore() 
at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) 
at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) 
at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__5() 
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0() 
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) 
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End() 
at System.Web.Mvc.MvcHandler.<>c__DisplayClasse.<EndProcessRequest>b__d() 
at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) 
at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) 
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) 
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) 
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Was it helpful?

Solution

Could you use Timestamps in your model and database table to track these values?

[Timestamp]
    public Byte[] Timestamp { get; set; }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top