Edit was unsuccessful. Please correct the errors and try again.

May 16, 2013 at 2:15 AM
Edited May 16, 2013 at 2:19 AM
Hi Guys,
            I am getting this error saving an object.
So the UI doesn;t show what the error is.
Also my break points are not being hit in the persisting or Updating methods.

How can I debug this?

Sorry I found this discussion!
https://nakedobjects.codeplex.com/discussions/282234


Regards,
            Alistair
Coordinator
May 16, 2013 at 11:25 AM
The discussion you are pointing to is 18 months ago - and that issue was fixed very shortly thereafter, so it is very unlikely to be the same thing.

First thing to check is: do you have any validate methods, and are any of them failing, but returning an empty string? (Returning null means 'OK', returning an empty string means 'not OK but no message' - in other words not very helpful.) As a second level, I suggest debugging with a breakpoint on every validate method and seeing what is failing. If it is definitely none of your validate methods, then please post the code for that complete class.
May 17, 2013 at 10:35 AM
Thanks Richard,
Sorry I was working on my services and getting them working with a separate interface assembly so I can mock my external services.

I am still getting this error,

I have implemented the Result Interface Association pattern and I guess thats working as EF is not complaining, I guess its an NO problem?

Actually my Validate method here does not seem to be working as I am not hitting a breakpoint in there.

Also I don't hit my breakpoints in the Persisting or Updating methods, can you help me here as well?
using System;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using NakedObjects;
using System.ComponentModel;
using Lansw.Uwas.Common.Enums;
using Lansw.Uwas.Common.Constants;
using Lansw.Uwas.Interfaces;

namespace Lansw.Uwas.Model
{
    //[IconName("cellphone.png")]
    [IconName("default.png")]    
    public class WorkOffer : BaseDomainObject
    {        
        private IPractitioner _selectedIPractitioner;        
        private ICollection<WorkOfferAudit> _workOfferAudits = new List<WorkOfferAudit>();
        
        #region Title       

        public override string ToString()
        {
            var t = new TitleBuilder();

            t.Append("Work Offer");

            if (SelectedPractitioner == null)
            {
                t.Append("New Work Offer");
            }
            else
            {
                t.Append("Work Offer For");
                t.Append(SelectedPractitioner);
            }
            return t.ToString();
        }

        #endregion Title

        #region Injected Services

        // This region should contain properties to hold references to any services required by the
        // object.  Use the 'injs' shortcut to add a new service.
        public WorkOfferRepository WorkOfferRepository { set; protected get; }
        public WorkOfferAuditRepository WorkOfferAuditRepository { set; protected get; }
        public OfficeRepository OfficeRepository { set; protected get; }
        public CourtRepository CourtRepository { set; protected get; }
        public IPractitionerService PractitionerService { set; protected get; }

        #endregion Injected Services

        #region Life Cycle Methods

        public virtual void Created() 
        {                                      
        }

       
        private void ResetMethodOfOfferSpecificCircumstances()
        {
            if (SelectedMethodOfOffer == MethodOfOffer.NextPractioner)
            {
                MethodOfOfferSpecificCircumstances = "NA";
            }            
        }

        public override void Persisting()
        {
            base.Persisting();
            ResetMethodOfOfferSpecificCircumstances();
            AuditWorkOfferChange(this);
        }

        public override void Updating()
        {
            base.Updating();

            ResetMethodOfOfferSpecificCircumstances();
            AuditWorkOfferChange(this);            
        }

        public void Persisted()
        {           
        }

        public void Updated()
        {           
        }

        private void AuditWorkOfferChange(WorkOffer workOffer)
        {
            var workOfferAudit = WorkOfferAuditRepository.NewWorkOfferAudit();

            //workOfferAudit.WorkOffer = workOffer;
            workOfferAudit.NewOfferState = workOffer.OfferState;

            Container.Persist(ref workOfferAudit); 

            WorkOfferAudits.Add(workOfferAudit);
                
        }

        #endregion Life Cycle Methods

        #region properties

        [Key]
        [Hidden]        
        public virtual int WorkOfferId { get; set; }        
        [MemberOrder(1), DisplayName("Legal Aid Office")]
        public virtual Office Office { get; set; }
        [MemberOrder(2), DisplayName("Court Venue")]
        public virtual Court Court { get; set; }
        [MemberOrder(3), DisplayName("Type Of Offer"), DefaultValue(TypeOfOffer.Duty)]
        public virtual TypeOfOffer TypeOfOffer { get; set; }
        [MemberOrder(4), DisplayName("Court Date")]     
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
        public virtual DateTime CourtDate  { get; set; }
        [MemberOrder(5), DisplayName("Person Making Offer")]
        public virtual string Offerer { get; set; }
        private MethodOfOffer _SelectedMethodOfOffer = MethodOfOffer.NextPractioner;
        [Hidden]
        public virtual MethodOfOffer SelectedMethodOfOffer
        {
            get
            {
                return (_SelectedMethodOfOffer);                
            }
            set
            {
                _SelectedMethodOfOffer = value;
            }
        }

        [MemberOrder(6), DisplayName("Method Of Offer")]
        public virtual string MethodOfOfferAsString { get; set; }

        
        [MemberOrder(8), DisplayName("Specific Practitioner Details")]
        [NotPersisted]
        public virtual IPractitioner SelectedIPractitioner
        {
            get { return _selectedIPractitioner; }
            set { _selectedIPractitioner = value; }
        }

        [Hidden]
        public virtual Practitioner SelectedPractitioner
        {
            get { return (Practitioner)_selectedIPractitioner; }
            set { _selectedIPractitioner = (IPractitioner)value; }
        }               

        [MemberOrder(9), DisplayName("Specific Practitioner LastName Filter")]
        [Optionally]
        public virtual string SpecificPractitionerLastNameFilter { get; set; }

        [MemberOrder(10), DisplayName("Exceptional Circumstances Requiring An offer To A Specific Practitioner"), DefaultValue(ConstantStrings.NotApplicable)]
        public virtual string MethodOfOfferSpecificCircumstances { get; set; }

        [MemberOrder(11), DisplayName("Work Offer State"), DefaultValue(OfferState.Pending)]
        public virtual OfferState OfferState { get; set; }

        [Hidden]
        public virtual ICollection<WorkOfferAudit> WorkOfferAudits
        {
            get { return _workOfferAudits; }
            set { _workOfferAudits = value; }
        }

        //[Hidden]
        //public virtual ICollection<WorkOfferAudit> WorkOfferAudits { get; private set; }

        #region Row Guid and Modified Date

        #region rowguid

        [Hidden]
        public override Guid rowguid { get; set; }

        #endregion rowguid

        #region ModifiedDate
      
        [Disabled]
        [ConcurrencyCheck] // This property will be used for concurrency checking i.e. to check if another user has updated
                           // the object before this copy of the object can be saved
        public override DateTime ModifiedDate { get; set; }

        #endregion ModifiedDate

        #endregion Row Guid and Modified Date
        #endregion properties
        
        #region Defaults
        
        public string DefaultMethodOfOfferAsString()
        {
            return Enum.GetName(typeof(MethodOfOffer), MethodOfOffer.NextPractioner);
        }
        
        #endregion Defaults

        #region Choices

        public List<Office> ChoicesOffice()
        {
            return OfficeRepository.ListAllOffices().ToList();
        }

        public IList<Court> ChoicesCourt(Office office)
        { 
            return CourtRepository.GetCourtsForOffice(office);
        }

        public IList<string> ChoicesMethodOfOfferAsString()
        {          
            return Enum.GetNames(typeof(MethodOfOffer)).ToList();
        }

        private MethodOfOffer SetSelectedMethodOfOffer(string methodOfOfferAsString)
        {
            if (string.IsNullOrEmpty(methodOfOfferAsString))
            {
                return (MethodOfOffer)Enum.Parse(typeof(MethodOfOffer), DefaultMethodOfOfferAsString());
            }
            return (MethodOfOffer)Enum.Parse(typeof(MethodOfOffer), methodOfOfferAsString);
        }
        
        /// <summary>
        /// ChoicesSelectedPractitioner 
        /// NB Unfortunately ChoicesXXX funtions can not take enums so we have to work around it like this,
        /// </summary>
        /// <param name="methodOfOfferAsString"></param>
        /// <param name="specificPractitionerLastNameFilter"></param>
        /// <returns></returns>
        public IList<IPractitioner> ChoicesSelectedIPractitioner(string methodOfOfferAsString, Court court,
                                        string specificPractitionerLastNameFilter) 
        {
            SelectedMethodOfOffer = SetSelectedMethodOfOffer(methodOfOfferAsString);
            return PractitionerService.GetSelectedMethodOfOfferPractitioners(SelectedMethodOfOffer, court, specificPractitionerLastNameFilter);
        }       

        #endregion Choices       

        #region Validate Methods

        public string ValidateMethodOfOfferSpecificCircumstances(string methodOfOfferSpecificCircumstances)
        {
            if (SelectedMethodOfOffer == MethodOfOffer.SpecificPractioner)
            {
                if ((methodOfOfferSpecificCircumstances == "NA") || (methodOfOfferSpecificCircumstances.Length == 0))
                {
                    return "A reason for the selected practitioner must be specified";
                }
            }
            return null;
        }

        #endregion Validate Methods           
    }
}
Regards,
            Alistair
May 17, 2013 at 11:14 AM
I still haven't changed all the references in to the source code project references but that will only be good when I get a crash to fix.
Coordinator
May 17, 2013 at 11:16 AM
Also I don't hit my breakpoints in the Persisting or Updating methods, can you help me here as well?
The error message indicates an edit failure - meaning that the input has not been accepted. So the the framework won't even have attempted to persist the object. So I would not expect Persisting or Updating to have been called.

I am not sure what the issue is though there is no reason at this stage to suspect it is a Naked Objects issue

To be honest, I think the real problem here is that you are attempting jump too far in one go. I suggest you build up your system in much smaller steps - but making sure that at each step you are doing the whole cycle each time i.e. getting through to persisting the objects (and using e.g. a simple repository to retrieve and look at them). Assuming you are working with code versioning and checking in very frequently, then you will know that the addition of a specific feature has caused the issue and can be more specific in where you are looking. i.e. if you've added a property, or a method and the system no longer completes the cycle - go back and confirm what the minimum change is that caused the problem, and you have a clue where to look.

If you haven't been working this way, then I recommend going back and starting from scratch - it will save you time in the long run.
May 18, 2013 at 7:25 AM
Dear Richard,
                   Sorry for the late reply, my account got shaped.
Yes I always try and do as you say and I also created a separate test object to test bits at time, I guess doing this is a bit more difficult with NO as things are more interconnected as all UI data comes from the model so model changes can affect any UI element, but thats a good thing.
But you are probably right I was probably moving too fast.
I would have thought that the framework might describe in some form more of what the problem is, its rather a generic message.

Best Regards,
                     Alistair



Coordinator
May 20, 2013 at 10:13 AM
I would have thought that the framework might describe in some form more of what the problem is, its rather a generic message.
When you have identified what was in fact causing the problem, if we can identify that scenario in the code and deliver a more helpful message we will.

Meantime, when you are debugging it, and in line with my response to an earlier posting of yours, I recommend that you switch logging on and read the log files.

(Also, I assume you have already tried temporarily setting VS to break on any exception?)
May 20, 2013 at 10:53 AM
Dear Richard,
                   I have narrowed the error down to something to do with my Practitioner association.
It looks like it is an EF problem as you dont seem to have a message for this error in the NO code.
I can use a direct simple reference to from my WorkOffer object to my Practitioner object so I dont need to use an interface association.
Can you give me any more debugging tips?
using System;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using NakedObjects;
using System.ComponentModel;
using Lansw.Uwas.Common.Enums;
using Lansw.Uwas.Common.Constants;
using Lansw.Uwas.Interfaces;
using System.Threading;

namespace Lansw.Uwas.Model
{
    //[IconName("cellphone.png")]
    [IconName("default.png")]    
    public class WorkOffer : BaseDomainObject
    {        
        private IPractitioner _IPractitioner;     
        //private ICollection<WorkOfferAudit> _workOfferAudits = new List<WorkOfferAudit>();
        
        #region Title       

        //public override string ToString()
        //{
        //    var t = new TitleBuilder();

        //    t.Append("Work Offer");

        //    if (SelectedPractitioner == null)
        //    {
        //        t.Append("New Work Offer");
        //    }
        //    else
        //    {
        //        t.Append("Work Offer For");
        //        t.Append(SelectedPractitioner);
        //    }
        //    return t.ToString();
        //}

        #endregion Title

        #region Injected Services

        // This region should contain properties to hold references to any services required by the
        // object.  Use the 'injs' shortcut to add a new service.
        public WorkOfferRepository WorkOfferRepository { set; protected get; }
        public WorkOfferAuditRepository WorkOfferAuditRepository { set; protected get; }        
        public IPractitionerService PractitionerService { set; protected get; }
        public IWindowsService WindowsService { set; protected get; }

        #endregion Injected Services

        #region Life Cycle Methods

        public virtual void Created() 
        {                            
        }

       
        //private void ResetMethodOfOfferSpecificCircumstances()
        //{
        //    if (SelectedMethodOfOffer == MethodOfOffer.NextPractioner)
        //    {
        //        MethodOfOfferSpecificCircumstances = "NA";
        //    }            
        //}

        public void Persisted()
        {
            WorkItem.WorkOffers.Add(this);

            //ResetMethodOfOfferSpecificCircumstances();
            //AuditWorkOfferChange(this);
        }

        //public override void Updating()
        //{
        //    base.Updating();

        //    ResetMethodOfOfferSpecificCircumstances();
        //    //AuditWorkOfferChange(this);            
        //}

        //public void Persisted()
        //{           
        //}

        //public void Updated()
        //{           
        //}

        //private void AuditWorkOfferChange(WorkOffer workOffer)
        //{
        //    var workOfferAudit = WorkOfferAuditRepository.NewWorkOfferAudit();

        //    //workOfferAudit.WorkOffer = workOffer;
        //    workOfferAudit.NewOfferState = workOffer.OfferState;

        //    Container.Persist(ref workOfferAudit); 

        //    WorkOfferAudits.Add(workOfferAudit);
                
        //}

        #endregion Life Cycle Methods

        #region properties

        [Key]
        [Hidden]        
        public virtual int WorkOfferId { get; set; }

        [Hidden]
        public virtual int WorkItemId { get; set; }

        [MemberOrder(1), DisplayName("Work Item")]
        [Optionally]
        public virtual WorkItem WorkItem { get; set; }

        [MemberOrder(2), DisplayName("Person Making Offer")]
        public virtual string Offerer
        {
            get { return UserName(); }
        }

        public string UserName()
        {
            return WindowsService.GetUserName();
        }

        private MethodOfOffer _SelectedMethodOfOffer = MethodOfOffer.NextPractioner;
        [Hidden]
        public virtual MethodOfOffer SelectedMethodOfOffer
        {
            get
            {
                return (_SelectedMethodOfOffer);
            }
            set
            {
                _SelectedMethodOfOffer = value;
            }
        }

        [MemberOrder(3), DisplayName("Method Of Offer")]
        public virtual string MethodOfOfferAsString { get; set; }


       __ [MemberOrder(4), DisplayName("Specific Practitioner Details")]
        public virtual Practitioner Practitioner { get; set; }
                

        [Hidden]
        public virtual long PractitionerId { get; set; }
__

        [MemberOrder(5), DisplayName("Specific Practitioner LastName Filter")]
        [Optionally]
        public virtual string SpecificPractitionerLastNameFilter { get; set; }

        [MemberOrder(6), DisplayName("Exceptional Circumstances Requiring An offer To A Specific Practitioner"), DefaultValue(ConstantStrings.NotApplicable)]
        public virtual string MethodOfOfferSpecificCircumstances { get; set; }

        [MemberOrder(7), DisplayName("Reply Time"), DefaultValue(ReplyTime.OneDay)]
        public virtual ReplyTime ReplyTime { get; set; }

        [MemberOrder(8), DisplayName("Work Offer State"), DefaultValue(OfferState.Pending)]
        public virtual OfferState OfferState { get; set; }


        #region Row Guid and Modified Date

        #region rowguid

        [Hidden]
        public override Guid rowguid { get; set; }

        #endregion rowguid

        #region ModifiedDate
      
        [Disabled]
        [ConcurrencyCheck] // This property will be used for concurrency checking i.e. to check if another user has updated
                           // the object before this copy of the object can be saved
        public override DateTime ModifiedDate { get; set; }

        #endregion ModifiedDate

        #endregion Row Guid and Modified Date
        #endregion properties
        
        #region Defaults
        
        public string DefaultMethodOfOfferAsString()
        {
            return Enum.GetName(typeof(MethodOfOffer), MethodOfOffer.NextPractioner);
        }
        
        #endregion Defaults

        #region Choices        

        public List<ReplyTime> ChoicesReplyTime() // Reply time needs to be ordered by the reply time values, default order is alphabetical
        {
            return (new List<ReplyTime>(Enum.GetValues(typeof(ReplyTime)).OfType<ReplyTime>()));
        }

        public IList<string> ChoicesMethodOfOfferAsString()
        {
            return Enum.GetNames(typeof(MethodOfOffer)).ToList();
        }

        private MethodOfOffer SetSelectedMethodOfOffer(string methodOfOfferAsString)
        {
            if (string.IsNullOrEmpty(methodOfOfferAsString))
            {
                return (MethodOfOffer)Enum.Parse(typeof(MethodOfOffer), DefaultMethodOfOfferAsString());
            }
            return (MethodOfOffer)Enum.Parse(typeof(MethodOfOffer), methodOfOfferAsString);
        }

        /// <summary>
        /// ChoicesIPractitioner 
        /// NB Unfortunately ChoicesXXX funtions can not take enums so we have to work around it like this,
        /// </summary>
        /// <param name="methodOfOfferAsString"></param>
        /// <param name="specificPractitionerLastNameFilter"></param>
        /// <returns></returns>
        __public List<Practitioner> ChoicesPractitioner(string methodOfOfferAsString, WorkItem workItem,
                                        string specificPractitionerLastNameFilter)
        {
            Court court = null;

            if (workItem != null)
            {
                court = workItem.Court;
            }
            SelectedMethodOfOffer = SetSelectedMethodOfOffer(methodOfOfferAsString);
            List<Practitioner> list = PractitionerService.GetSelectedMethodOfOfferPractitioners(SelectedMethodOfOffer, court, specificPractitionerLastNameFilter).ToList().ConvertAll(x => (Practitioner)x);
            return list;
        }
__
      

        #endregion Choices       


        #region Validate Methods
       

        #endregion Validate Methods           
    }
Coordinator
May 20, 2013 at 11:29 AM
One tip is: if you are having any trouble persisting a transient object, can you:

a) Retrieve an already persisted object of that type OK. In other words, assuming that the generated database schema looks OK (if not, that's where your trouble is) then add one or more rows of data into the database directly, including FK associations as needed, then just use a SimpleRepository to retrvieve and display them.

b) If that works, try updating a persistent object - including changing its simple values, and then changing its associations (but to other objects that already exist in the database).

I have found that this can often reveal the source of an error more clearly than when trying to create and persist the object in the first place,