Acumatica中从Graph1触发操作批量写入其他表的推荐实现方案
Great question! In Acumatica, sticking to the framework's built-in patterns is key to maintaining data integrity, enforcing business logic, and keeping your code maintainable. Here's the recommended approach for your scenario:
1. Use Graph Instances Instead of Direct PXDatabase Calls
Adding Data Views for Table2/Table3 to Graph1 isn't necessary, but leveraging their dedicated graphs (Graph2 and Graph3) is the best practice. This ensures all validation rules, event handlers (like RowInserted, FieldUpdated), and system field auto-population (e.g., CreatedByID, CreatedDateTime) are executed—something direct PXDatabase.Insert would bypass, risking inconsistent data.
Here's how to implement this:
- Create instances of Graph2 and Graph3 using
PXGraph.CreateInstance<T>()(since they're not dependencies of Graph1). - Add your batch records to each graph's primary Data View.
- Call
PressSave()on each graph to commit the changes.
2. Wrap All Operations in PXTransactionScope
To guarantee atomicity (either all inserts succeed or none do), wrap the entire workflow in a PXTransactionScope. This handles database transaction management and automatic rollback if any step fails.
Example Code Snippet
public PXAction<Table1> BatchInsertRecords; [PXButton] [PXUIField(DisplayName = "Batch Insert to Table2/3")] protected void batchInsertRecords() { using (var transactionScope = new PXTransactionScope()) { var currentTable1Record = Base.Table1Records.Current; if (currentTable1Record == null) return; // Insert batch records into Table2 via Graph2 var graph2 = PXGraph.CreateInstance<Graph2>(); foreach (var table2Record in GenerateTable2Records(currentTable1Record)) { graph2.Table2Records.Insert(table2Record); } graph2.PressSave(); // Insert batch records into Table3 via Graph3 var graph3 = PXGraph.CreateInstance<Graph3>(); foreach (var table3Record in GenerateTable3Records(currentTable1Record)) { graph3.Table3Records.Insert(table3Record); } graph3.PressSave(); // Commit the entire transaction transactionScope.Complete(); // Refresh Graph1 to reflect any related changes Base.Table1Records.View.RequestRefresh(); } } // Helper method to generate Table2 records private IEnumerable<Table2> GenerateTable2Records(Table1 sourceRecord) { // Replace with your logic to create multiple Table2 records yield return new Table2 { Table2Field1 = sourceRecord.Table1FieldA, Table2Field2 = DateTime.Now, // Populate all required fields here }; yield return new Table2 { Table2Field1 = sourceRecord.Table1FieldB, Table2Field2 = DateTime.Now, }; } // Helper method to generate Table3 records private IEnumerable<Table3> GenerateTable3Records(Table1 sourceRecord) { // Similar logic for Table3 records yield return new Table3 { Table3FieldX = sourceRecord.Table1FieldC, Table3FieldY = "Batch Inserted" }; }
When Might You Use PXDatabase.Insert?
Only consider direct PXDatabase.Insert if Table2 and Table3 have zero business logic, validation rules, or event handlers. Even then, using the graph approach is safer for future changes—if someone adds logic to those tables later, your code will automatically respect it without modification.
内容的提问来源于stack exchange,提问作者Joseph Caruana

