Skip to content

Latest commit

 

History

History
179 lines (151 loc) · 9.3 KB

PX1036.md

File metadata and controls

179 lines (151 loc) · 9.3 KB

PX1036

This document describes the PX1036 diagnostic.

Summary

Code Short Description Type Code Fix
PX1036 The DAC must have one primary key, which should be named PK. The class containing DAC foreign keys should be named FK. The single unique key in the DAC should be named UK. If the DAC has multiple unique keys, they should be declared in a public static class named UK. Warning (ISV Level 3: Informational) Available

Diagnostic Description

The diagnostic checks the correct naming of primary, foreign, and unique key field declarations in DACs. For a primary key, the name should be PK. For a foreign key, the name can be arbitrary but the key should be declared in a public static class called FK. For a single unique key, the name should be UK. Multiple unique keys in the DAC can have arbitrary names but they must be declared in a public static class called UK. The warning is shown only for DACs that have an attribute derived from the PXCacheName attribute, or an attribute derived from the PXPrimaryGraphBase attribute such as PXPrimaryGraphAttribute. The diagnostic does not check abstract DACs or DACs that have only unbound DAC properties (fully unbound DACs used for custom pop-ups and filters for inquiry forms).

The diagnostic also checks the declaration and implementation of a unique key by using the following rules:

  • A single unique key in a DAC declaration must have the name UK.
  • Multiple unique keys can have arbitrary names but they must be declared inside a public static class named UK.
  • The primary key differs from unique keys only by two things: Its name is PK, and its set of fields consists of all DAC key properties (DAC properties marked with IsKey = true). The DAC should not have any unique key declarations without a primary key declaration. Acuminator searches for an appropriate candidate for a primary key among the DAC unique keys. It looks for a unique key whose set of fields is composed of all DAC key properties.
    • If there is a suitable unique key in the DAC, Acuminator suggests that you turn it into a primary key named PK by renaming it and optionally changing its location to make it a first DAC's type member. This logic is applied for unique keys that are not direct DAC type members because they are declared in the nested UK container class.
    • If there is no appropriate unique key, Acuminator shows an error for the PX1033 diagnostic indicating the missing primary key.

To fix the issue, change the name of the primary key class to PK, make sure that all foreign key classes are declared in a public static class called FK, and declare the unique keys as described in the rules above.

The code fix suggests that you do the following:

  • Change the name of a suitable unique key class to PK if there is no primary key class declaration in the DAC
  • Place all foreign keys in a public static class named FK
  • Change the name of the single unique key to UK
  • Place all unique keys in a public static class named UK

For foreign keys, the diagnostic searches for a public static class named FK. There could be three possible outcomes:

  • The FK class is not found. Then the diagnostic suggests to generate it and move all DAC foreign keys there.
  • The FK class is found and it is public and static. The diagnositc suggests to move all DAC foreign key declarations which are not already inside the FK class into the found class.
  • The FK class is found but it is not declared correctly (not public or static). In this case, the diagnositc does not suggest a code fix.

Example of Incorrectly Named Primary Key

An example of an incorrectly named primary key is shown in the following code.

Example of Incorrect Code

[PXCacheName("Sales Order")]
public class SOOrder : PXBqlTable, IBqlTable
{
	public class IncorrectPKName : PrimaryKeyOf<SOOrder>.By<orderType, orderNbr>
	{
		public static SOOrder Find(PXGraph graph, string orderType, string orderNbr) => FindBy(graph, orderType, orderNbr);
	}
	
	[PXDBString(IsKey = true, InputMask = "")]
	[PXDefault]
	[PXUIField(DisplayName = "Order Type")]
	public string OrderType { get; set; }
	public abstract class orderType : IBqlField { }
	[PXDBString(IsKey = true, InputMask = "")]
	[PXDefault]
	[PXUIField(DisplayName = "Order Nbr.")]
	public string OrderNbr { get; set; }
	public abstract class orderNbr : IBqlField { }
	[PXStringList(new[] { "N", "O" }, new[] { "New", "Open" })]
	[PXDBString]
	[PXUIField(DisplayName = "Status")]
	public string Status { get; set; }
	public abstract class status : IBqlField { }
	[PXDBTimestamp]
	public virtual byte[] tstamp { get; set; }
	public abstract class Tstamp : IBqlField { }
}

Example of Fixed Code

An example of a corrected primary key is shown in the following code.

[PXCacheName("SO Order")]
public class SOOrder : PXBqlTable, IBqlTable
{
	public class PK : PrimaryKeyOf<SOOrder>.By<orderType, orderNbr>
	{
		public static SOOrder Find(PXGraph graph, string orderType, string orderNbr) => FindBy(graph, orderType, orderNbr);
	}
	
	[PXDBString(IsKey = true, InputMask = "")]
	[PXDefault]
	[PXUIField(DisplayName = "Order Type")]
	public string OrderType { get; set; }
	public abstract class orderType : IBqlField { }
	[PXDBString(IsKey = true, InputMask = "")]
	[PXDefault]
	[PXUIField(DisplayName = "Order Nbr.")]
	public string OrderNbr { get; set; }
	public abstract class orderNbr : IBqlField { }
	[PXStringList(new[] { "N", "O" }, new[] { "New", "Open" })]
	[PXDBString]
	[PXUIField(DisplayName = "Status")]
	public string Status { get; set; }
	public abstract class status : IBqlField { }
	[PXDBTimestamp]
	public virtual byte[] tstamp { get; set; }
	public abstract class Tstamp : IBqlField { }
}

Example of Multiple Unique Key Declarations Without a Primary Key Declaration

Example of Incorrect Code

An example of multiple unique key declarations without a primary key declaration is shown in the following code.

[PXCacheName("INUnit")]
public partial class INUnitMultipleUniqueKeysNoPK : PXBqlTable, IBqlTable
{
	public static class UK
	{
		public class ByAll : PrimaryKeyOf<INUnitMultipleUniqueKeysNoPK>.By<unitType, fromUnit, toUnit, inventoryID, itemClassID>
		{
			public static INUnitMultipleUniqueKeysNoPK Find(PXGraph graph, short? unitType, string fromUnit, string toUnit, int? inventoryID, int? itemClassID) =>
			   FindBy(graph, unitType, fromUnit, toUnit, inventoryID, itemClassID);
		}

		public class ByGlobal : PrimaryKeyOf<INUnitMultipleUniqueKeysNoPK>.By<unitType, fromUnit, toUnit>
		{
			public static INUnitMultipleUniqueKeysNoPK Find(PXGraph graph, string fromUnit, string toUnit) => FindBy(graph, INUnitType.Global, fromUnit, toUnit);			
		}

		public class ByInventory : PrimaryKeyOf<INUnitMultipleUniqueKeysNoPK>.By<unitType, inventoryID, fromUnit>
		{
			public static INUnitMultipleUniqueKeysNoPK Find(PXGraph graph, int? inventoryID, string fromUnit) => FindBy(graph, INUnitType.InventoryItem, inventoryID, fromUnit);		
		}

		public class ByItemClass : PrimaryKeyOf<INUnitMultipleUniqueKeysNoPK>.By<unitType, itemClassID, fromUnit>
		{
			public static INUnitMultipleUniqueKeysNoPK Find(PXGraph graph, int? itemClassID, string fromUnit) => FindBy(graph, INUnitType.ItemClass, itemClassID, fromUnit);
		}
	}
	 
	...
}

Example of Fixed Code

An example of multiple unique key declarations where one declaration was turned into a primary key declaration is shown in the following code.

[PXCacheName("INUnit")]
public partial class INUnitMultipleUniqueKeysNoPK : PXBqlTable, IBqlTable
{
	public class PK : PrimaryKeyOf<INUnitMultipleUniqueKeysNoPK>.By<unitType, fromUnit, toUnit, inventoryID, itemClassID>
	{
		public static INUnitMultipleUniqueKeysNoPK Find(PXGraph graph, short? unitType, string fromUnit, string toUnit, int? inventoryID, int? itemClassID) =>
		   FindBy(graph, unitType, fromUnit, toUnit, inventoryID, itemClassID);
	}

	public static class UK
	{

		public class ByGlobal : PrimaryKeyOf<INUnitMultipleUniqueKeysNoPK>.By<unitType, fromUnit, toUnit>
		{
			public static INUnitMultipleUniqueKeysNoPK Find(PXGraph graph, string fromUnit, string toUnit) => FindBy(graph, INUnitType.Global, fromUnit, toUnit);			
		}

		public class ByInventory : PrimaryKeyOf<INUnitMultipleUniqueKeysNoPK>.By<unitType, inventoryID, fromUnit>
		{
			public static INUnitMultipleUniqueKeysNoPK Find(PXGraph graph, int? inventoryID, string fromUnit) => FindBy(graph, INUnitType.InventoryItem, inventoryID, fromUnit);		
		}

		public class ByItemClass : PrimaryKeyOf<INUnitMultipleUniqueKeysNoPK>.By<unitType, itemClassID, fromUnit>
		{
			public static INUnitMultipleUniqueKeysNoPK Find(PXGraph graph, int? itemClassID, string fromUnit) => FindBy(graph, INUnitType.ItemClass, itemClassID, fromUnit);
		}
	}
	
	...
}

Related Articles

Primary Key

To Define a Primary Key

PXCacheNameAttribute Class

PXPrimaryGraphAttribute Class