1616 5) Query and join data across tables
1717 6) Clean up (delete tables)
1818
19+ Note: The last step (cleanup) automatically deletes all demo tables.
20+ Comment out the cleanup() call in run_demo() if you want to keep the
21+ tables in your environment for inspection.
22+
1923Why pandas DataFrames?
2024 This example uses client.dataframe (pandas) instead of raw dict/list CRUD
2125 because DataFrames provide significant advantages for multi-record operations:
5357
5458from PowerPlatform .Dataverse .client import DataverseClient
5559
56- # -- Table schema names (prefixed to avoid collisions) --
57- PREFIX = f"demo_{ uuid .uuid4 ().hex [:6 ]} "
58- TABLE_CUSTOMER = f"{ PREFIX } _Customer"
59- TABLE_PROJECT = f"{ PREFIX } _Project"
60- TABLE_TASK = f"{ PREFIX } _Task"
61- TABLE_TIMEENTRY = f"{ PREFIX } _TimeEntry"
60+ # -- Table schema names --
61+ # Uses the standard 'new_' publisher prefix (default Dataverse publisher).
62+ # A unique suffix avoids collisions with existing tables.
63+ SUFFIX = uuid .uuid4 ().hex [:6 ]
64+ TABLE_CUSTOMER = f"new_DemoCustomer{ SUFFIX } "
65+ TABLE_PROJECT = f"new_DemoProject{ SUFFIX } "
66+ TABLE_TASK = f"new_DemoTask{ SUFFIX } "
67+ TABLE_TIMEENTRY = f"new_DemoTimeEntry{ SUFFIX } "
6268
6369# -- Output folder for exported data (relative to this script) --
6470_SCRIPT_DIR = Path (__file__ ).resolve ().parent
@@ -100,19 +106,19 @@ def run_demo(client):
100106 print (f"[INFO] Output folder: { OUTPUT_DIR .resolve ()} " )
101107
102108 # -- Step 1: Create 4 tables --
103- step1_create_tables (client )
109+ primary_name_col = step1_create_tables (client )
104110
105111 # -- Step 2: Create relationships --
106112 step2_create_relationships (client )
107113
108114 # -- Step 3: Populate with sample data --
109- customer_ids , project_ids , task_ids = step3_populate_data (client )
115+ customer_ids , project_ids , task_ids = step3_populate_data (client , primary_name_col )
110116
111117 # -- Step 4: Query and analyze --
112- step4_query_and_analyze (client , customer_ids )
118+ step4_query_and_analyze (client , customer_ids , primary_name_col )
113119
114120 # -- Step 5: Update and delete --
115- step5_update_and_delete (client , task_ids )
121+ step5_update_and_delete (client , task_ids , primary_name_col )
116122
117123 # -- Step 6: Cleanup --
118124 cleanup (client )
@@ -134,15 +140,18 @@ def step1_create_tables(client):
134140 print ("-" * 60 )
135141
136142 # Customer table
137- client .tables .create (
143+ result = client .tables .create (
138144 TABLE_CUSTOMER ,
139145 {
140146 f"{ TABLE_CUSTOMER } _Email" : "string" ,
141147 f"{ TABLE_CUSTOMER } _Industry" : "string" ,
142148 f"{ TABLE_CUSTOMER } _Revenue" : "money" ,
143149 },
144150 )
145- print (f"[OK] Created table: { TABLE_CUSTOMER } " )
151+ # The primary name column logical name is returned by tables.create()
152+ # so we know exactly what key to use in create payloads.
153+ primary_name_col = result .primary_name_attribute
154+ print (f"[OK] Created table: { TABLE_CUSTOMER } (primary column: { primary_name_col } )" )
146155
147156 # Project table
148157 client .tables .create (
@@ -176,7 +185,10 @@ def step1_create_tables(client):
176185 },
177186 )
178187 print (f"[OK] Created table: { TABLE_TIMEENTRY } " )
179- print (f"[OK] All 4 tables created with prefix '{ PREFIX } '" )
188+ print (f"[OK] All 4 tables created (suffix: { SUFFIX } )" )
189+ print (f"[INFO] Primary name column: '{ primary_name_col } '" )
190+
191+ return primary_name_col
180192
181193
182194# ================================================================
@@ -225,7 +237,7 @@ def step2_create_relationships(client):
225237# ================================================================
226238
227239
228- def step3_populate_data (client ):
240+ def step3_populate_data (client , primary_name_col ):
229241 """Create sample records using client.dataframe.create().
230242
231243 Why DataFrames here instead of client.records.create()?
@@ -252,10 +264,8 @@ def step3_populate_data(client):
252264 print ("-" * 60 )
253265
254266 # -- Customers --
255- # Note: The primary column logical name is {prefix}_name (lowercase),
256- # and custom column logical names follow the same lowercase convention.
257- # The SDK lowercases keys automatically, so we use the schema names here.
258- name_col = f"{ PREFIX } _Name"
267+ # Use the primary name column returned by tables.create()
268+ name_col = primary_name_col
259269 customers_df = pd .DataFrame (
260270 [
261271 {
@@ -364,15 +374,15 @@ def step3_populate_data(client):
364374# ================================================================
365375
366376
367- def step4_query_and_analyze (client , customer_ids ):
377+ def step4_query_and_analyze (client , customer_ids , primary_name_col ):
368378 """Query data and demonstrate DataFrame analysis."""
369379 print ("\n " + "-" * 60 )
370380 print ("STEP 4: Query and analyze data" )
371381 print ("-" * 60 )
372382
373383 # Query all projects as a DataFrame
374384 # Note: select uses logical names (lowercase). The SDK lowercases automatically.
375- name_attr = f" { PREFIX } _name" # primary column logical name
385+ name_attr = primary_name_col
376386 projects = client .dataframe .get (
377387 TABLE_PROJECT ,
378388 select = [
@@ -437,7 +447,7 @@ def step4_query_and_analyze(client, customer_ids):
437447# ================================================================
438448
439449
440- def step5_update_and_delete (client , task_ids ):
450+ def step5_update_and_delete (client , task_ids , primary_name_col ):
441451 """Demonstrate update and delete with DataFrames."""
442452 print ("\n " + "-" * 60 )
443453 print ("STEP 5: Update and delete records" )
@@ -461,10 +471,9 @@ def step5_update_and_delete(client, task_ids):
461471 print (f"[OK] Deleted 1 task" )
462472
463473 # Verify
464- name_attr = f"{ PREFIX } _name"
465474 remaining = client .dataframe .get (
466475 TABLE_TASK ,
467- select = [name_attr , status_col ],
476+ select = [primary_name_col , status_col ],
468477 )
469478 print (f"\n Remaining tasks ({ len (remaining )} ):" )
470479 print (f"{ remaining .to_string (index = False )} " )
0 commit comments