Skip to content

Latest commit

 

History

History
166 lines (124 loc) · 7.9 KB

File metadata and controls

166 lines (124 loc) · 7.9 KB

PX1069

This document describes the PX1069 diagnostic.

Summary

Code Short Description Type Code Fix
PX1069 The DAC must declare mandatory timestamp and audit DAC fields. Error Available

Diagnostic Description

Data Access Classes (DACs) in Acumatica Framework must declare mandatory system fields that are required for proper concurrent updates handling, data tracking and audit functionality. These mandatory fields include:

  • tstamp: A timestamp field for optimistic concurrency control in the concurrent database update scenarios.
  • CreatedByID: The ID of the user who created the record.
  • CreatedByScreenID: The screen ID from which the record was created.
  • CreatedDateTime: The date and time when the record was created.
  • LastModifiedByID: The ID of the user who last modified the record.
  • LastModifiedByScreenID: The screen ID from which the record was last modified.
  • LastModifiedDateTime: The date and time when the record was last modified.

The PX1069 diagnostic determines whether any of these mandatory fields are missing from a DAC and reports an error. If multiple mandatory fields are missing, the diagnostic reports all missing fields in a single error message.

Exceptions when Mandatory Fields are Not Required

There are some exceptions to the PX069 diagnostic when the mandatory fields are not required, and thus the diagnostic will not be triggered. The diagnostic is not triggered in the following cases:

  • The DAC has the PXAccumulator attribute or an attribute derived from the PXAccumulator attribute. Such DACs are used for special scenarios that involve accumulation of data. These scenarios are handled differently by the Acumatica Framework. Thus, DACs with the PXAccumulator attribute do not require audit or timestamp fields.

  • The DAC has the PXProjection attribute or an attribute derived from the PXProjection attribute. These DACs (also called projection DACs) usually represent readonly database views or complex queries rather than direct table mappings. Such read-only projection DACs do not require audit or timestamp fields.

    However, Acumatica also supports writable projection DACs (also called persistent projection DACs). Such DACs also must declare audit and timestamp fields! Currently, the PX1069 diagnostic does not report the absence of these fields in projection DACs.

  • The DAC is fully unbound from the database, meaning there are no tables in the database that correspond to it. Such DACs are also known as virtual DACs. They do not require audit or timestamp fields because they do not interact with the database directly and do not persist any audit data.

How Fully Unbound DACs are Determined

Since Acuminator does not access the database, it determines whether a DAC is fully unbound based on the following rules:

  • A DAC without any DAC fields or with only unbound DAC fields is considered fully unbound.
  • A DAC marked with PX.Data.PXVirtualAttribute is always considered fully unbound even if it has DB bound fields.
  • A DAC marked with PX.Data.PXProjectionAttribute, PX.Data.PXAccumulatorAttribute or any other attribute derived from PX.Data.PXDBInterceptorAttribute is always considered DB bound even if it has only unbound fields.
  • A DAC with a DB bound NoteID field is considered fully unbound if NoteID is the only DB bound field in the DAC and all other fields in the DAC are unbound.

Code Fix Behavior

The PX1069 code fix automatically adds the missing mandatory fields to the DAC. The code fix intelligently inserts missing mandatory DAC fields according to the following rules:

  • Audit fields are grouped together, with the Created audit fields placed before Last Modified audit fields. The fix respects the locations of existing audit fields and adds missing fields in the appropriate positions within the audit field group.
  • The missing tstamp field is placed at the end of the DAC field declaration.
  • The code fix preserves the region directives of the existing DAC fields.
  • Appropriate using directives (System and PX.Data.BQL) are automatically added if needed.
  • The code fix supports the context of nullable reference types and emits the correct nullable annotation for generated DAC fields if nullable reference types are enabled.

Example of Incorrect Code

using System;
using PX.Data;

[PXCacheName("Incomplete DAC")]
public class IncompleteDac : PXBqlTable, IBqlTable
{
	#region DacID
	public abstract class dacID : PX.Data.BQL.BqlInt.Field<dacID> { }
	
    [PXDBIdentity(IsKey = true)]
	public virtual int? DacID { get; set; }
	#endregion

	#region Description
	public abstract class description : PX.Data.BQL.BqlString.Field<description> { }
	
    [PXDBString(255)]
	public virtual string Description { get; set; }
	#endregion

	// Missing mandatory fields: tstamp, CreatedByID, CreatedByScreenID, CreatedDateTime,
	// LastModifiedByID, LastModifiedByScreenID, LastModifiedDateTime
}

Example of Code Fix

using System;
using PX.Data;
using PX.Data.BQL;

[PXCacheName("Incomplete DAC")]
public class IncompleteDac : PXBqlTable, IBqlTable
{
	#region DacID
	[PXDBIdentity(IsKey = true)]
	public virtual int? DacID { get; set; }
	public abstract class dacID : PX.Data.BQL.BqlInt.Field<dacID> { }
	#endregion

	#region Description
	[PXDBString(255)]
	public virtual string Description { get; set; }
	public abstract class description : PX.Data.BQL.BqlString.Field<description> { }
	#endregion

	#region CreatedByID
	public abstract class createdByID : BqlGuid.Field<createdByID> { }

	[PXDBCreatedByID]
	public virtual Guid? CreatedByID { get; set; }
	#endregion

	#region CreatedByScreenID
	public abstract class createdByScreenID : BqlString.Field<createdByScreenID> { }

	[PXDBCreatedByScreenID]
	public virtual string CreatedByScreenID { get; set; }
	#endregion

	#region CreatedDateTime
	public abstract class createdDateTime : BqlDateTime.Field<createdDateTime> { }

	[PXDBCreatedDateTime]
	public virtual DateTime? CreatedDateTime { get; set; }
	#endregion

	#region LastModifiedByID
	public abstract class lastModifiedByID : BqlGuid.Field<lastModifiedByID> { }

	[PXDBLastModifiedByID]
	public virtual Guid? LastModifiedByID { get; set; }
	#endregion

	#region LastModifiedByScreenID
	public abstract class lastModifiedByScreenID : BqlString.Field<lastModifiedByScreenID> { }

	[PXDBLastModifiedByScreenID]
	public virtual string LastModifiedByScreenID { get; set; }
	#endregion

	#region LastModifiedDateTime
	public abstract class lastModifiedDateTime : BqlDateTime.Field<lastModifiedDateTime> { }

	[PXDBLastModifiedDateTime]
	public virtual DateTime? LastModifiedDateTime { get; set; }
	#endregion

	#region tstamp
	public abstract class Tstamp : BqlByteArray.Field<Tstamp> { }

	[PXDBTimestamp]
	public virtual byte[] tstamp { get; set; }
	#endregion
}

Related Articles