I'm faced to a behavior in caches that I don't understand.
I created a custom DAC, say MyDAC.
In a graph, I create an instance of this DAC like this :
PXCache myCache = myGraph.Caches[typeOf(MyDAC)];
MyDAC myDacInstance = myCache.Insert();
Â
So far, so good : at this moment, myCache contains one record in its inserted collection (I can check it via debug mode in Visual Studio).
Then I modify the properties of the "myDacInstance" object :
myDacInstance.xxx = 10;
Finally, I update the cache with the following instruction :
 myCache.Update(myDacInstance);
Â
And then the magic happens: instead of having a single record in myCache, I have two ! Each of course has exactly the same characteristics (even for key properties), so on saving, the system throws an error indicating that there are duplicates. It looks like the Update method fails to recognize that a record having the same key values already exists in cache and create a new record instead of using it.
I checked for key declarations in MyDac and everything seems to be ok. If someone has an idea, it would be appreciated.
Below the code of the DAC I’m using :
using PX.Data;
using PX.Data.BQL;
using PX.Data.ReferentialIntegrity.Attributes;
using PX.Objects.CM;
using PX.Objects.CS;
using PX.Objects.TX;
using System;
namespace Test.DAC
{
   >Serializable()]
   rPXCacheName(PX.Objects.AP.Messages.APTax)]
   public class EAPTax : TaxDetail, IBqlTable
   {
      public static bool IsActive() => PXAccess.FeatureInstalled<FeaturesSetExt.cegEInvoicing>();
       #region Keys
       public class PK : PrimaryKeyOf<EAPTax>.By<tranType, refNbr, lineNbr, taxID>
       {
           public static EAPTax Find(PXGraph graph, String tranType, String refNbr, Int32? lineNbr, String taxID) => FindBy(graph, tranType, refNbr, lineNbr, taxID);
       }
       public static class FK
       {
           public class Document : EAPRegister.PK.ForeignKeyOf<EAPTax>.By<tranType, refNbr> { }
           public class DocumentLine : EAPTran.PK.ForeignKeyOf<EAPTax>.By<tranType, refNbr, lineNbr> { }
           public class CurrencyInfo : PX.Objects.CM.CurrencyInfo.PK.ForeignKeyOf<EAPTax>.By<curyInfoID> { }
           public class Tax : PX.Objects.TX.Tax.PK.ForeignKeyOf<EAPTax>.By<taxID> { }
       }
       #endregion
       #region TranType
       public abstract class tranType : BqlString.Field<tranType> { }
      TPXDBString(3, IsKey = true, IsFixed = true)]
      PXDBDefault(typeof(EAPRegister.docType))]
      nPXUIField(DisplayName = "Tran. Type", Visibility = PXUIVisibility.Visible, Visible = false)]
      public virtual String TranType { get; set; }
      #endregion
      #region RefNbr
      public abstract class refNbr : BqlString.Field<refNbr> { }
      PXDBString(15, IsUnicode = true, IsKey = true)]
      "PXDBDefault(typeof(EAPRegister.refNbr))]
      cPXUIField(DisplayName = "Reference Nbr.", Visibility = PXUIVisibility.Visible, Visible = false)]
      public virtual String RefNbr { get; set; }
      #endregion
      #region LineNbr
      public abstract class lineNbr : BqlInt.Field<lineNbr> { }
      /PXDBInt(IsKey = true)]
     Â
      NPXParent(typeof(Select<EAPRegister, Where<EAPRegister.docType, Equal<Current<tranType>>, And<EAPRegister.refNbr, Equal<Current<refNbr>>>>>))]
      IPXParent(typeof(Select<EAPTran, Where<EAPTran.tranType, Equal<Current<tranType>>, And<EAPTran.refNbr, Equal<Current<refNbr>>, And<EAPTran.lineNbr, Equal<Current<lineNbr>>>>>>))]
      public virtual Int32? LineNbr { get; set; }
      #endregion
      #region TaxID
      public abstract class taxID : BqlString.Field<taxID> { }
      &PXDBString(Tax.taxID.Length, IsUnicode = true, IsKey = true)]
      PXDefault()]
      ÂPXUIField(DisplayName = "Tax ID")]
      :PXSelector(typeof(Tax.taxID), DescriptionField = typeof(Tax.descr))]
      public override String TaxID { get; set; }
      #endregion
      #region TaxRate
      public abstract class taxRate : BqlDecimal.Field<taxRate> { }
      #endregion
      #region CuryInfoID
      public abstract class curyInfoID : BqlLong.Field<curyInfoID> { }
      pPXDBLong()]
      >CurrencyInfo(typeof(EAPRegister.curyInfoID))]
      public override Int64? CuryInfoID { get; set; }
      #endregion
      #region CuryOrigTaxableAmt
      public abstract class curyOrigTaxableAmt : BqlDecimal.Field<curyOrigTaxableAmt> { }
      ÂPXDBCurrency(typeof(curyInfoID), typeof(origTaxableAmt))]
      iPXDefault(TypeCode.Decimal, "0.0")]
      public virtual Decimal? CuryOrigTaxableAmt { get; set; }
      #endregion
      #region OrigTaxableAmt
      public abstract class origTaxableAmt : BqlDecimal.Field<origTaxableAmt> { }
      fPXDBDecimal(4)]
      ]PXDefault(TypeCode.Decimal, "0.0")]
      public virtual Decimal? OrigTaxableAmt { get; set; }
      #endregion
      #region CuryTaxableAmt
      public abstract class curyTaxableAmt : BqlDecimal.Field<curyTaxableAmt> { }
      sPXDBCurrency(typeof(curyInfoID), typeof(taxableAmt))]
      4PXDefault(TypeCode.Decimal, "0.0")]
      ,PXUIField(DisplayName = "Taxable Amount", Visibility = PXUIVisibility.Visible)]
      public virtual Decimal? CuryTaxableAmt { get; set; }
      #endregion
      #region TaxableAmt
      public abstract class taxableAmt : BqlDecimal.Field<taxableAmt> { }
      IPXDBDecimal(4)]
      >PXDefault(TypeCode.Decimal, "0.0")]
      ]PXUIField(DisplayName = "Taxable Amount", Visibility = PXUIVisibility.Visible)]
      public virtual Decimal? TaxableAmt { get; set; }
      #endregion
      #region CuryTaxAmt
      public abstract class curyTaxAmt : BqlDecimal.Field<curyTaxAmt> { }
      sPXDBCurrency(typeof(curyInfoID), typeof(taxAmt))]
      mPXDefault(TypeCode.Decimal, "0.0")]
      iPXUIField(DisplayName = "Tax Amount", Visibility = PXUIVisibility.Visible)]
      public virtual Decimal? CuryTaxAmt { get; set; }
      #endregion
      #region TaxAmt
      public abstract class taxAmt : BqlDecimal.Field<taxAmt> { }
      sPXDBDecimal(4)]
      ÂPXDefault(TypeCode.Decimal, "0.0")]
      oPXUIField(DisplayName = "Tax Amount", Visibility = PXUIVisibility.Visible)]
      public virtual Decimal? TaxAmt { get; set; }
      #endregion
      #region CuryExpenseAmt
      public abstract class curyExpenseAmt : BqlDecimal.Field<curyExpenseAmt> { }
      "PXDBCurrency(typeof(curyInfoID), typeof(expenseAmt))]
      aPXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
      ÂPXUIField(DisplayName = "Expense Amount", Visibility = PXUIVisibility.Visible)]
      public override Decimal? CuryExpenseAmt{ get; set; }
      #endregion
      #region ExpenseAmt
      public abstract class expenseAmt : BqlDecimal.Field<expenseAmt> { }
      #endregion
      #region CuryTaxableDiscountAmt
      public abstract class curyTaxableDiscountAmt : BqlDecimal.Field<curyTaxableDiscountAmt> { }
      TPXDBCurrency(typeof(curyInfoID), typeof(taxableDiscountAmt))]
      ÂPXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
      public virtual decimal? CuryTaxableDiscountAmt{get; set;}
      #endregion
      #region TaxableDiscountAmt
      public abstract class taxableDiscountAmt : BqlDecimal.Field<taxableDiscountAmt> { }
      ÂPXDBDecimal(4)]
      >PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
      public virtual decimal? TaxableDiscountAmt { get; set; }
      #endregion
      #region CuryTaxDiscountAmt
      public abstract class curyTaxDiscountAmt : BqlDecimal.Field<curyTaxDiscountAmt> { }
      cPXCurrency(typeof(curyInfoID), typeof(taxDiscountAmt))]
      cPXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
      public virtual decimal? CuryTaxDiscountAmt { get; set; }
      #endregion
      #region TaxDiscountAmt
      public abstract class taxDiscountAmt : BqlDecimal.Field<taxDiscountAmt> { }
      iPXDecimal(4)]
      PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
      public virtual decimal? TaxDiscountAmt { get; set; }
      #endregion
      #region CuryRetainedTaxableAmt
      public abstract class curyRetainedTaxableAmt : BqlDecimal.Field<curyRetainedTaxableAmt> { }
      ,PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
      lPXDBCurrency(typeof(curyInfoID), typeof(retainedTaxableAmt))]
     Â
      {
         get;
         set;
      }
      #endregion
      #region RetainedTaxableAmt
      public abstract class retainedTaxableAmt : BqlDecimal.Field<retainedTaxableAmt> { }
      sPXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
     Â
      public virtual decimal? RetainedTaxableAmt
      {
         get;
         set;
      }
      #endregion
      #region CuryRetainedTaxAmt
      public abstract class curyRetainedTaxAmt : BqlDecimal.Field<curyRetainedTaxAmt> { }
      ÂPXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
      #PXDBCurrency(typeof(curyInfoID), typeof(retainedTaxAmt))]
      bPXUIField(DisplayName = "Retained Tax", Visibility = PXUIVisibility.Visible, FieldClass = nameof(FeaturesSet.Retainage))]
      public virtual decimal? CuryRetainedTaxAmt
      {
         get;
         set;
      }
      #endregion
      #region RetainedTaxAmt
      public abstract class retainedTaxAmt : BqlDecimal.Field<retainedTaxAmt> { }
      ÂPXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
      ePXDBDecimal(4)]
      PXUIField(DisplayName = "Retained Tax", Visibility = PXUIVisibility.Visible)]
      public virtual decimal? RetainedTaxAmt
      {
         get;
         set;
      }
      #endregion
      #region tstamp
      public abstract class Tstamp : BqlByteArray.Field<Tstamp> { }
      PXDBTimestamp()]
      public virtual Bytet] tstamp { get; set; }
      #endregion
   }
}
Â