Loading ...

Property From Cropportunity Is Not Loaded

Hello everybody,

today I want to leave short note on issue with CROpportunity DAC class.

For quite a few times I've noticed that someone adds field to CROpportunity, but later notices that field is lost either on moment of loading from database, or lost during persisting record to database.

Reason for such weirdness is that starting from some Acumatica version CROpportunity got following declaration:

	[System.SerializableAttribute()]
	[PXCacheName(Messages.Opportunity)]
	[PXPrimaryGraph(typeof(OpportunityMaint))]
	[CREmailContactsView(typeof(Select2<Contact,
		LeftJoin<BAccountOn<BAccount.bAccountIDEqual<Contact.bAccountID>>>,
		Where2<Where<Optional<CROpportunity.bAccountID>, IsNullAnd<Contact.contactID
Equal<Optional<CROpportunity.contactID>>>>,    Or2<Where<Optional<CROpportunity.bAccountID>, IsNotNull
And<Contact.bAccountIDEqual<Optional<CROpportunity.bAccountID>>>>, Or<Contact.contactTypeEqual<ContactTypesAttribute.employee>>>>>))] [PXEMailSource]//NOTE: for assignment map [PXProjection(typeof(Select2<Standalone.CROpportunity, InnerJoin<Standalone.CROpportunityRevisionOn<Standalone.CROpportunityRevision.noteID
Equal<Standalone.CROpportunity.defQuoteID>>, LeftJoin<Standalone.CRQuote, On<Standalone.CRQuote.quoteIDEqual<Standalone.CROpportunity.defQuoteID>>>>>), new Type[] { typeof(Standalone.CROpportunity), typeof(Standalone.CROpportunityRevision) } )]     public partial class CROpportunity : IBqlTableIAssignIPXSelectableINotable {

List of applied attributes is pretty heavy and can be confusing, but reason of such losts live in this part:

[PXProjection(typeof(Select2<Standalone.CROpportunity,
	InnerJoin<Standalone.CROpportunityRevisionOn<Standalone.CROpportunityRevision.noteIDEqual<Standalone.CROpportunity.defQuoteID>>,
	LeftJoin<Standalone.CRQuote,
		On<Standalone.CRQuote.quoteIDEqual<Standalone.CROpportunity.defQuoteID>>>>>),
	new Type[] { typeof(Standalone.CROpportunity), typeof(Standalone.CROpportunityRevision) }
	)]	

As you can see, CROpportunity has decoration of PXProjection. I have one more sample of PXProjection on my blog.

But coming back, how to deal with data loss? Answer is simple: you'll need to make extension for two DAC classes, instead of one. 

Below goes code sample of what I've did for one of my customers:

    public class CROpportunityExt : PXCacheExtension<CROpportunity>
    {
		#region UsrContractLength
		[PXDBInt]
		[PXUIField(DisplayName = "Contract Duration ")]
                [PXDefault(0)]
		public virtual int? UsrContractDuration { getset; }
		public abstract class usrContractDuration : IBqlField { }
		#endregion

and one more cache extension:

public class CROpportunityStandAloneCSEXt : PXCacheExtension<PX.Objects.CR.Standalone.CROpportunity>
{
    #region UsrContractLength
    [PXDBInt]
    [PXUIField(DisplayName = "Contract Duration")]
    [PXDefault(0)]
    public virtual int? UsrContractDuration { getset; }
    public abstract class usrContractDuration : IBqlField { }
    #endregion

Summary

As usually if field doesn't arrive from db or not to db the problem is in forgeting of DB prefix. Instead of PXDBInt quite often is typed ( or probably would say copy/pasted ) PXInt. Another common reason is override of PXView with delegate, and forgetting of including newly added column in the output, or sometime if delegate has plenty of conditional statements then not including some field into those statements list. Third reason is or could be FieldSelecting/FieldUpdating/RowUpdated behavior which can "kill" value. And fourth by commonality but not by complexity reason can be issues when you have PXProjection over DAC class.