Data table optimization

The following is not meant as a tutorial, nor a best practice, but rather an example to illustrate previous statements.
for what I will often do for an item/Inventory system

USTRUCT(BlueprintType)
struct FSimpleItem
{
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FString PublicName;
	// name for internal lookup, and sorting
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int32 InternalID = 0;
	// how many of the item is held (primarily for consumables, but stacking can be a thing)
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int32 Quantity = 1;
    //...
};

then later I define

/**
 * Definition for Items
 */
USTRUCT(BlueprintType)
struct FItemDef : public FSimpleItem
{
	GENERATED_BODY()
public:
	// Blueprint of the item (Mesh, Materials, EffectEmitters)
	// holding special logic for the item.
	// held as softClass so that it can be instanced multiple times then created and removed on the fly through repositories and asset manager
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSoftClassPtr<class ASpawnItemBase> ItemBlueprint;
//...
};

this approach to use Data Tables I need to define a

USTRUCT(BlueprintType)
struct FItemDataTableRow : public FTableRowBase
{
	GENERATED_USTRUCT_BODY()
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FString PublicName = TEXT("");
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int32 InternalID = 0;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSoftClassPtr<class ASpawnItemBase> itemBlueprint;
//...
};

then you declare either in the second one, so the other is in context scope, or like in some static maybe BlueprintLibrary you declare/define some helper functions for conversion and resolution.

the inventory is just a glorified wrapper on TArray<FSimpleItem> and equip slots are ASpawnItemBase* where the ASpawnItemBase “has-a” FItemDef

notice in the FItemDataTableRow I don’t declare what the row name is that is defined in the DataTable itself (either in the editor, or in the CSV/JSon) then whenever I want a DataTable row based on the an InternalID I do an atoi() on internalID convert it to an FName to quarry the Table, and then when I get the Row I do a sanity check to see
if(Item.internalID == Row.InternalID) (if it fails I write error messages to the designers because they are the ones that messed up) then I go to async load the TSoftClassPtr just in case say the player wants to spontaneously equip something.