Add rows to UDataTable at runtime with c++ code

Hi,
I am currently developing a plugin on the basis of the c++ API of Unreal Engine. Unfortunately I’m stuck at one point and can’t get any further. What I want in short: I want to read out XML files, create Datatable assets from that data and use this datatable assets on gameobjects later to manage some behaviour. All of that should be done at plugin runtime, i.e. when the plugin is executed. I am already able to receive data from a specified XML file and to create and register a UDataTable asset, so that it appears in the Content Browser and assign a UScriptStruct to it. But how do I add new rows to this table? The documentation is not particularly informative at this point. I found the AddRow() function, which sounds like it would do what I want. However, this function expects an FTableRowBase instance next to the name of the new row and I don’t know how to add data this way. FTableRowBase only has a default constructor. If I use this and use the created instance as a parameter in AddRow(), I can’t open the created Datatable asset anymore (Unreal Engine crashes with an error message that a memory address can’t be accessed anymore). Another idea of mine was to use the UScriptStruct I assigned to the UDataTable asset, thinking that all Row structures must inherit from FTableRowBase. However, then there is a compiler error.

I really hope someone can help me to add data to my empty datatable asset using the c++ API.

Take a look at DataTableCSV.cpp, specifically FDataTableImporterCSV::ReadTable(). It’s constructing table rows from CSV data using the table’s script struct.

1 Like

@anonymous_user_4aa5607e1 pointed me in the right direction

@philippn_vfx if you want to import data from text then FDataTableImporterCSV::ReadTable() is great to learn, but if you have created your custom Row class deriving from FTableRowBase then all code from that method could be simplified into simple loop:

TArray<FYourRowStruct> DataToInsert;

for (int32 RowIdx = 0; RowIdx < DataToInsert.Num(); RowIdx++)
	{
		// Get row name
		FName RowName = DataTableUtils::MakeValidName(FString::Printf(TEXT("%d"),RowIdx + 1));
		DataTable->AddRow(RowName, DataToInsert[RowIdx]);//This will remove existing rows with this name if found
}
1 Like

To add data to a DataTable you can create a new instance of your UScriptStruct. You can set the struct’s properties as needed to represent the data you want to add to the DataTable.

Create a new FTableRowBase instance and cast it to your UScriptStruct. This is necessary because DataTables in Unreal Engine store data as FTableRowBase instances.

TSharedPtr NewRow = MakeShared();
*NewRow = *MyStructInstance;

Get a reference to the DataTable asset you want to add data to. You can do this using the LoadObject function or by finding it using FindObject or StaticLoadObject.

UDataTable* MyDataTable = LoadObject(nullptr, TEXT(“Path/To/My/DataTable”));

Call the AddRow function on the DataTable with the name of the new row and the FTableRowBase instance you created earlier.

MyDataTable->AddRow(TEXT(“NewRowName”), NewRow);

Save the DataTable asset to disk to persist the changes.

MyDataTable->MarkPackageDirty();
MyDataTable->PostEditChange();

this is just an example, and you may need to modify this code to your specific use case.
also, make sure to handle any errors that may occur when loading or saving assets to prevent crashes or data loss. :eyes:

3 Likes

Would like to share how to add a row to a Data Table that is using blueprint structs.
Unfortunately this only works in editor and can’t do a packaged build with it.
In the header file:

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, meta = (CustomStructureParam = "Struct"))
	void AddToDataTable(UDataTable* inDatatable, FName inRowName, const FString& JsonStructString);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	void RemoveDataTableRow(UDataTable* inDatatable, FName inRowName);

In the C++ file

void U::AddToDataTable_Implementation(UDataTable* inDatatable, FName inRowName,const FString& JsonStructString)
{
	FString localDatabaseString = inDatatable->GetTableAsJSON();
	FString localJsonStruct = JsonStructString;

	localDatabaseString.RemoveAt(localDatabaseString.Len()-1,1,true);
	localJsonStruct.RemoveAt(0,1,true);

	localJsonStruct = ",{\"Name\": \"" + inRowName.ToString() + "\"," + localJsonStruct;
	localDatabaseString = localDatabaseString + localJsonStruct + "]";
	
	inDatatable->CreateTableFromJSONString(localDatabaseString);
}

void U::RemoveDataTableRow_Implementation(UDataTable* inDatatable, FName inRowName)
{
	inDatatable->RemoveRow(inRowName);
}

Screenshot 2024-02-16 145305

Just enable Json Blueprint Utilities Plugin