问题
I defined several new screens in Acumatica 2018R2 and need to enable attribute support according the class assigned to the transaction. The class screen appears to allow attaching attributes, but the transactional screen does not display any attribute. I found several examples on Stack Overflow, but the only clue I see seems to be that if the class id cannot be determined then no attributes will show. However, upon debug, I see that the class id is found.
This is my test code where I have tried stripping down to a very basic test.
AAClass
using PX.Data;
using System;
namespace Attributes
{
[Serializable]
public class AAClass : IBqlTable
{
#region ClassID
[PXDBIdentity]
[PXUIField(DisplayName = "Class ID")]
public virtual int? ClassID { get; set; }
public abstract class classID : IBqlField { }
#endregion
#region ClassCD
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Class CD")]
public virtual string ClassCD { get; set; }
public abstract class classCD : IBqlField { }
#endregion
#region Descr
[PXDBString(256, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Descr")]
public virtual string Descr { get; set; }
public abstract class descr : IBqlField { }
#endregion
#region CreatedByID
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
public abstract class createdByID : IBqlField { }
#endregion
#region CreatedByScreenID
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
public abstract class createdByScreenID : IBqlField { }
#endregion
#region CreatedDateTime
[PXDBCreatedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldCreatedDateTime)]
public virtual DateTime? CreatedDateTime { get; set; }
public abstract class createdDateTime : IBqlField { }
#endregion
#region LastModifiedByID
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
public abstract class lastModifiedByID : IBqlField { }
#endregion
#region LastModifiedByScreenID
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
public abstract class lastModifiedByScreenID : IBqlField { }
#endregion
#region LastModifiedDateTime
[PXDBLastModifiedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldLastModifiedDateTime)]
public virtual DateTime? LastModifiedDateTime { get; set; }
public abstract class lastModifiedDateTime : IBqlField { }
#endregion
#region Tstamp
[PXDBTimestamp()]
public virtual byte[] Tstamp { get; set; }
public abstract class tstamp : IBqlField { }
#endregion
#region NoteID
[PXNote]
public virtual Guid? NoteID { get; set; }
public abstract class noteID : IBqlField { }
#endregion
}
}
AAClassMaint
using PX.Data;
using PX.Objects.CR;
namespace Attributes
{
public class AAClassMaint : PXGraph<AAClassMaint, AAClass>
{
#region Data Views
[PXViewName("Classes")]
public PXSelect<AAClass> Classes;
[PXViewName("Attributes")]
public CSAttributeGroupList<AAClass, AATag> Mapping;
#endregion
}
}
AATag
using PX.Data;
using PX.Objects.CR;
using PX.Objects.CS;
using System;
namespace Attributes
{
[Serializable]
public class AATag : IBqlTable
{
#region TagID
[PXDBIdentity]
public virtual int? TagID { get; set; }
public abstract class tagID : IBqlField { }
#endregion
#region TagCD
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Tag ID")]
public virtual string TagCD { get; set; }
public abstract class tagCD : IBqlField { }
#endregion
#region MyClassID
[PXDBInt()]
[PXSelector(
typeof(AAClass.classID),
typeof(AAClass.classCD),
typeof(AAClass.descr),
SubstituteKey = typeof(AAClass.classCD)
)]
[PXUIField(DisplayName = "My Class ID")]
public virtual int? MyClassID { get; set; }
public abstract class myClassID : IBqlField { }
#endregion
#region CreatedByID
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
public abstract class createdByID : IBqlField { }
#endregion
#region CreatedByScreenID
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
public abstract class createdByScreenID : IBqlField { }
#endregion
#region CreatedDateTime
[PXDBCreatedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldCreatedDateTime)]
public virtual DateTime? CreatedDateTime { get; set; }
public abstract class createdDateTime : IBqlField { }
#endregion
#region LastModifiedByID
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
public abstract class lastModifiedByID : IBqlField { }
#endregion
#region LastModifiedByScreenID
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
public abstract class lastModifiedByScreenID : IBqlField { }
#endregion
#region LastModifiedDateTime
[PXDBLastModifiedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldLastModifiedDateTime)]
public virtual DateTime? LastModifiedDateTime { get; set; }
public abstract class lastModifiedDateTime : IBqlField { }
#endregion
#region Tstamp
[PXDBTimestamp()]
public virtual byte[] Tstamp { get; set; }
public abstract class tstamp : IBqlField { }
#endregion
#region NoteID
[PXNote]
public virtual Guid? NoteID { get; set; }
public abstract class noteID : IBqlField { }
#endregion
#region Attributes
public abstract class attributes : IBqlField { }
[CRAttributesField(typeof(AATag.myClassID))]
public virtual string[] Attributes { get; set; }
public virtual int? ClassID
{
get { return MyClassID; }
}
#endregion
}
}
AATagEntry
using PX.Data;
using PX.Objects.CR;
namespace Attributes
{
public class AATagEntry : PXGraph<AATagEntry, AATag>
{
#region Data Views
[PXViewName("Classes")]
public PXSelect<AATag> Tags;
[PXViewName("Answers")]
public CRAttributeList<AATag> Answers;
#endregion
}
}
As I understand the various posts for this topic, the key requirements are:
Define MAPPING in the class maintenance screen
[PXViewName("Attributes")] public CSAttributeGroupList<AAClass, AATag> Mapping;
Define ANSWERS in the transactional entry screen
[PXViewName("Answers")] public CRAttributeList<AATag> Answers;
Include NoteID in the transactional table
Add ATTRIBUTES to the transactional table, including a field for ClassID
public abstract class attributes : IBqlField { } [CRAttributesField(typeof(AATag.myClassID))] public virtual string[] Attributes { get; set; } public virtual int? ClassID { get { return MyClassID; } }
回答1:
CRAttributesField
attribute will build a request with the generic type (classIdField) provided in it's parameter. In your case that would be AATag.myClassID
:
protected static Type GetAttributesSearchCommand(Type classIdField)
{
var cmd = BqlCommand.Compose(typeof (Search2<,,>), typeof (CSAttribute.attributeID),
typeof (InnerJoin<,>), typeof (CSAttributeGroup),
typeof (On<,>), typeof (CSAttributeGroup.attributeID), typeof (Equal<>),
typeof (CSAttribute.attributeID),
typeof(Where<,,>), typeof(CSAttributeGroup.entityType), typeof(Equal<>), typeof(Required<>), typeof(CSAttributeGroup.entityType),
typeof (And<,>), typeof (CSAttributeGroup.entityClassID), typeof (Equal<>), typeof (Current<>),
classIdField);
return cmd;
}
So the key part of the request where clause will be:
And<CSAttributeGroup.entityClassID, Equal<Current<AATag.myClassID>>>
This means you must have a current AATag record in memory:
Caches[typeof(AATag)].Current
I suggest you first trace the value (Help->Trace window) to validate it's non null:
public void AATag_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
if (e.Row is AATag)
{
PXTrace.WriteInformation(((AATag)e.Row).myClassID);
}
}
If it is null, you will have to join AATag in the relevant DataView (preferred) or set it explicitely in some events. Using Acumatica Request Profiler (SM205070 ) can also help to determine why the request is not returning any record.
回答2:
As HB_Acumatica suggested in the comments, the issue appeared to be with the ClassID fields being defined as integer.
I removed the original ClassID (int) fields and renamed the ClassCD (string) fields in the Class DAC's. Next, I changed the ClassID fields in the transactional DAC's to strings. Problem solved. The attribute tab on the transactional entry screens now display the attributes assigned to the class selected.
Lesson learned: A "Class" DAC should not have a ClassID/ClassCD pair, but rather a simple string ClassID field. (Typically named specific to the type of class, i.e. TagClassID) The Class ID used in the transactional tables will then use the string Class ID.
来源:https://stackoverflow.com/questions/55599118/how-do-i-enable-custom-attributes-can-assign-on-class-but-not-displaying-for