Data Binding with EF Core
Entity Framework Core is the standard way to talk to a database in modern .NET — and Wisej.NET binds it straight to your UI. This course shows you how to wire entities to controls with clean two-way binding, validation and responsive async loading. You'll connect EF Core models to grids and editors, keep the UI responsive while data loads in the background, validate input on the way in, and persist changes safely.
Wire entities to the UI with two-way binding, validation and async loads.
- Level: Intermediate
- Duration: 9h
- Modules: 7
Curriculum
Module 1: Architecture: EF Core inside a Wisej.NET Application
Module 1 of Data Binding with EF Core — wire entities to the UI with two-way binding, validation and async loads. Read the lesson guide and the lab / exam guide, watch the DbContext lifetime walkthrough, pass the knowledge check, then complete the hands-on lab in the Support Desk Data Console.
- ReadingLesson Guide · 14 min
Where EF Core belongs in a stateful Wisej.NET app: session, UI, request and unit-of-work lifetimes, a DbContextFactory with one context per operation, the Microsoft DI bridge, and the session-safety rules. What this means for a Wisej.NET developer working with real databases — and how to read this module.
- ReadingLab / Exam Guide · 10 min
What you'll build in the hands-on lab, the suggested approach, and the required deliverables.
- Video lessonWhere the DbContext lives in a Wisej.NET app · 14 min
Where the DbContext lives in a Wisej.NET app — a guided Module 1 walkthrough, built step by step in the Support Desk Data Console. Runs right here in the player.
Narration transcript
Begin the Support Desk Data Console by deciding which objects live for a session and which live for one database operation. Wisej.NET forms retain user state, but an Entity Framework database context should represent a short unit of work.
The server-side programming model feels familiar because controls, event handlers, and binding sources stay together. Do not give the context that same lifetime. Create it for a query or change, save when needed, then dispose it instead of keeping it as interface state.
Separate session state, interface objects, individual requests, and database work. An awaited operation may resume on another thread, and a context is not thread-safe. Keeping it in a long-lived form also retains tracked entities long after the operation that needed them.
Use AddDbContextFactory as the default so search, lookup, save, and delete can each own a fresh context. A longer-lived modal-editor context is a deliberate exception: keep it private, guard access, and dispose it when that editor closes.
Register the context factory in the dependency-injection provider using configured connection information. Bridge that provider into Wisej.NET so pages resolve the same registered services. Restrict diagnostic settings to development and avoid introducing a second competing service container.
TicketQueryService stores the factory, not a shared context. Each method creates and disposes its own context before returning. This prevents one user’s tracked changes from sharing a context with another user’s query and avoids concurrent access to that context.
Keep selected records, filters, pending edits, and binding sources inside their session. Shared static storage is appropriate only for genuinely shared immutable material, such as reference data. A background operation also creates its own context instead of borrowing the form’s state.
Count demonstrates the whole operation boundary. The loading guard prevents a second submission while a fresh context counts the tickets. When the database is unavailable, the friendly error explains the failure and the final cleanup restores the button for another attempt.
Build the solution layers and factory registration, then resolve the query service from a page and run the asynchronous count. Include the design-time factory. Your review should be able to identify where every context is created and disposed, with no static context anywhere.
- ReadingAI Coding Exercise · 20 min
Build this module's SupportDesk sample with ChatGPT or Claude from a ready-made prompt that points the model at this module's specification, then review, run and extend what it gives you — including against our own reference build on GitHub.
- Knowledge checkModule 1 Knowledge Check · 10 min · Pass mark 80%
- Hands-on labLab — Solution Skeleton and First Async Query · 45 min
Objective: Create the Support Desk Data Console solution with Web, Data, Services and Tests projects, add the EF Core provider packages to the data project, create SupportDeskContext with a design-time factory, register AddDbContextFactory in ASP.NET Core startup and expose Microsoft's IServiceProvider to Wisej.NET, then resolve a query service from a Wisej.NET Page and run a first async count query behind a loading flag and an error message, without binding anything yet. Deliverables: Solution with Web, Data, Services and Tests projects and the EF Core provider packages; SupportDeskContext registered through AddDbContextFactory with a design-time factory; Microsoft IServiceProvider exposed to Wisej.NET and a query service resolved from a Page; First async count query with a loading guard and an error message; No static DbContext anywhere in the solution.
Module 2: Modeling, DbContext Configuration, and Migrations
Module 2 of Data Binding with EF Core — wire entities to the UI with two-way binding, validation and async loads. Read the lesson guide and the lab / exam guide, watch the Model, RowVersion and the first migration walkthrough, pass the knowledge check, then complete the hands-on lab in the Support Desk Data Console.
- ReadingLesson Guide · 14 min
Entities shaped for data-bound screens, Fluent API for keys, lengths, indexes, delete behaviour and RowVersion, migrations as reviewed source with scripts and bundles, and the design-time factory. What this means for a Wisej.NET developer working with real databases — and how to read this module.
- ReadingLab / Exam Guide · 10 min
What you'll build in the hands-on lab, the suggested approach, and the required deliverables.
- Video lessonModel, RowVersion and the first migration · 14 min
Model, RowVersion and the first migration — a guided Module 2 walkthrough, built step by step in the Support Desk Data Console. Runs right here in the player.
Narration transcript
Define the Support Desk schema before relying on data-bound screens. The Entity Framework model connects interface expectations with database rules. Configuring relationships, indexes, and concurrency deliberately makes that contract reviewable instead of leaving it to accidental defaults.
Look at the failures the schema must prevent: an unindexed queue search, two agents overwriting one ticket, and a manually patched database diverging from the next release. Each problem calls for a different model or migration decision.
Keep Ticket at the center of the entity relationships, with small lookup entities and comments as its detail. The optional agent and version value carry distinct meanings. Use a separate flat list item for the grid instead of exposing the whole graph.
Use simple annotations where they are sufficient, and collect production database configuration in OnModelCreating. The fluent configuration expresses lengths, required values, indexes, precision, defaults, and relationship behavior together, keeping database mapping decisions close to the context.
Require a bounded title and configure RowVersion for concurrency. Build indexes around the searches the application actually performs, including status with due date. Explicit delete behavior makes the effect on related records a reviewed choice instead of a surprise.
The update matches both the ticket identifier and the version originally read. If another agent changed that version, no row matches. Entity Framework reports a concurrency conflict, allowing the application to explain the collision instead of silently replacing someone else’s work.
Review a migration like any other source change before applying it. Development can apply the reviewed migration directly; production receives an approved repeatable script or bundle. This keeps schema changes tied to release review rather than several application instances racing at startup.
Give the design-time factory the same provider with a safe local development connection. Migration tooling can then build the model without starting Wisej.NET. Separating this path makes schema generation independent of the application’s runtime startup behavior.
Generate InitialCreate, inspect the planned changes, then apply them to create the tables, version column, and indexes. Seed through one short-lived context. The resulting sample customers, agents, categories, and tickets give later binding lessons a consistent database to use.
Deliver the five related entities with explicit delete rules, the planned indexes, and RowVersion. Add the design-time factory and reviewed initial migration, then seed the development database. The hand-in should demonstrate that the model and generated schema agree.
- ReadingAI Coding Exercise · 20 min
Build this module's SupportDesk sample with ChatGPT or Claude from a ready-made prompt that points the model at this module's specification, then review, run and extend what it gives you — including against our own reference build on GitHub.
- Knowledge checkModule 2 Knowledge Check · 10 min · Pass mark 80%
- Hands-on labLab — Model, Migration and Seed Data · 45 min
Objective: Create the Customer, Agent, Category, Ticket and TicketComment entities for the Support Desk Data Console, configure relationships and delete behaviours with the Fluent API, configure RowVersion with IsRowVersion, add indexes for Status, DueDate, CustomerId and UpdatedAt, add a design-time factory, create the InitialCreate migration, and seed five customers, three agents, categories and at least fifty tickets into a local SQLite or SQL Server LocalDB database. Deliverables: Customer, Agent, Category, Ticket and TicketComment entities with relationships and delete behaviours; RowVersion configured with IsRowVersion; Indexes for Status, DueDate, CustomerId and UpdatedAt; Design-time factory and the InitialCreate migration; Seed data: five customers, three agents, categories and at least fifty tickets.
Module 3: Loading Data into BindingSource, DataGridView, and Lookup Controls
Module 3 of Data Binding with EF Core — wire entities to the UI with two-way binding, validation and async loads. Read the lesson guide and the lab / exam guide, watch the ticket browser walkthrough, pass the knowledge check, then complete the hands-on lab in the Support Desk Data Console.
- ReadingLesson Guide · 14 min
Async LINQ execution, no-tracking projection to list items, BindingSource as the UI bridge, never binding an IQueryable, loading flags around async handlers, and lookup ComboBoxes with DisplayMember and ValueMember. What this means for a Wisej.NET developer working with real databases — and how to read this module.
- ReadingLab / Exam Guide · 10 min
What you'll build in the hands-on lab, the suggested approach, and the required deliverables.
- Video lessonThe ticket browser: async search bound through BindingSource · 14 min
The ticket browser: async search bound through BindingSource — a guided Module 3 walkthrough, built step by step in the Support Desk Data Console. Runs right here in the player.
Narration transcript
Build a ticket browser that loads asynchronously and binds its results through BindingSource. The screen needs a stable list for display, while the query service needs only a short database operation. Separating those responsibilities keeps interface state independent of the context.
Select just the fields needed by the seven grid columns into TicketListItem. A no-tracking projection returns less data and avoids retaining an editable entity graph. The browser list can then outlive the query context without becoming part of the editor’s work.
Compose the query before executing it: add the filters, ordering, page boundaries, and projection. ToListAsync then materializes the requested results once. This gives the database the filtering and paging work instead of loading everything and trimming it in the interface.
Inside TicketQueryService, create one context and add only the filters the user selected. Count the matches, then retrieve the projected page. The query remains a description until the asynchronous execution points, making its database work explicit in the method.
Bind the materialized list to BindingSource and bind the grid to that source. Do not hand the grid a live database set. Load lookup choices before the first search and distinguish their displayed text from the key stored as the selected value.
The page coordinates the user experience around one awaited service call. Set the loading guard, disable commands, and show status before loading. Assign the returned list, then restore the controls in finally so success and failure both leave a usable page.
Search with text and status, then compare the fifty visible rows with the total match count. Next Page performs another query with a new page boundary. Only projected results reach the browser; the server does not transfer the underlying entity graph.
Test the unreachable-server path deliberately. The operator should receive a useful message and regain Search after cleanup. A later attempt creates a fresh context, so a failed operation does not leave the screen tied to a failed database object.
Deliver the browser with its list model, search criteria, query service, and bound grid. Load lookups first and include search, forward, and backward paging with a total count. Verify loading guards and recovery as part of the same workflow.
- ReadingAI Coding Exercise · 20 min
Build this module's SupportDesk sample with ChatGPT or Claude from a ready-made prompt that points the model at this module's specification, then review, run and extend what it gives you — including against our own reference build on GitHub.
- Knowledge checkModule 3 Knowledge Check · 10 min · Pass mark 80%
- Hands-on labLab — Ticket Browser · 45 min
Objective: Build the Support Desk ticket browser: TicketListItem and TicketSearchCriteria records, a SearchTicketsAsync method that composes AsNoTracking, Where, OrderBy, Skip, Take and Select before ToListAsync, a DataGridView bound through a BindingSource to TicketListItem, lookup ComboBoxes for status and customer loaded before the first search, Search, Next Page and Previous Page buttons, a total count and page size display, and a loading guard that keeps the UI usable after errors. Deliverables: TicketListItem and TicketSearchCriteria records with SearchTicketsAsync; DataGridView bound to TicketListItem through a BindingSource; Filtering and paging composed in the query so the database does the work; Lookup ComboBoxes loaded before the first search, showing names and storing keys; Search, Next Page and Previous Page buttons with a total count and a loading guard.
Module 4: Two-Way Binding and CRUD Editors
Module 4 of Data Binding with EF Core — wire entities to the UI with two-way binding, validation and async loads. Read the lesson guide and the lab / exam guide, watch the ticket editor walkthrough, pass the knowledge check, then complete the hands-on lab in the Support Desk Data Console.
- ReadingLesson Guide · 14 min
DataBindings and BindingSource in editors, EndEdit, CancelEdit, AddNew and RemoveCurrent, direct entity binding versus edit-model binding, and save, cancel, delete and reload flows that end in SaveChangesAsync. What this means for a Wisej.NET developer working with real databases — and how to read this module.
- ReadingLab / Exam Guide · 10 min
What you'll build in the hands-on lab, the suggested approach, and the required deliverables.
- Video lessonThe ticket editor: EndEdit, map, SaveChangesAsync · 14 min
The ticket editor: EndEdit, map, SaveChangesAsync — a guided Module 4 walkthrough, built step by step in the Support Desk Data Console. Runs right here in the player.
Narration transcript
Turn the ticket dialog into a safe editing boundary. The user gets familiar Save, Cancel, and Delete commands, while the server controls when input reaches the model and when Entity Framework writes it. The modal form should not become a permanent database context.
Before saving or deleting, enforce the server’s part of the contract: finish pending edits, create a fresh context for the operation, and prevent duplicate submissions. A familiar dialog is reliable only when these hidden steps agree with what the buttons promise.
Connect the controls to TicketEditModel through BindingSource and choose when each value updates. Text and dates update on validation; lookups update as their property changes. BindingSource editing methods manage the current item, but none of them replaces a database save.
Choose the binding boundary according to the editor’s responsibilities. Direct entity binding can suit one short-lived aggregate with a private context. An edit model makes validation and permitted partial updates explicit, and avoids treating a read-only grid projection as an editable entity.
Follow one save sequence: guard, finish edits, validate, load or create with a fresh context, map allowed values, and save. Close successfully only after persistence succeeds. Handle concurrency separately from other database failures so the user receives the right explanation.
In SaveAsync, inspect the order rather than just the method names. EndEdit must precede validation; context creation follows accepted input. Loading by key and mapping from the edit model define what is written, while finally releases the saving guard on every exit.
Delete starts with confirmation, then reloads the ticket by key in a fresh context. If it has already disappeared, explain that instead of treating it as a normal removal. Check the business rule before removing and saving the record.
Change the title and urgency in the modal editor, then save. The busy state covers persistence, and a successful dialog result closes the editor. The parent browser searches again, so its displayed row comes from the saved database state rather than assumptions about the edit.
Build add and edit forms around TicketEditModel, BindingSource, and ErrorProvider. Include loading, guarded save, confirmed deletion, and the parent refresh. Verify that cancelling an edit and completing a successful save produce different, predictable effects on the browser.
- ReadingAI Coding Exercise · 20 min
Build this module's SupportDesk sample with ChatGPT or Claude from a ready-made prompt that points the model at this module's specification, then review, run and extend what it gives you — including against our own reference build on GitHub.
- Knowledge checkModule 4 Knowledge Check · 10 min · Pass mark 80%
- Hands-on labLab — Add and Edit Ticket Forms · 45 min
Objective: Build the Add Ticket and Edit Ticket modal forms for the Support Desk Data Console: a TicketEditModel, a TicketEditorForm with a BindingSource and an ErrorProvider, TextBox, ComboBox, DateTimePicker and CheckBox properties bound to the model, LoadEditorAsync for new and existing tickets, SaveAsync that calls EndEdit, a validation placeholder, mapping and SaveChangesAsync, Delete with confirmation and a fresh entity load, and a parent grid that refreshes after DialogResult.OK. Deliverables: TicketEditModel and TicketEditorForm with a BindingSource and an ErrorProvider; TextBox, ComboBox, DateTimePicker and CheckBox properties bound to the edit model; LoadEditorAsync for new and existing tickets and SaveAsync with EndEdit, mapping and SaveChangesAsync; Delete with confirmation, a fresh entity load and graceful handling of already-deleted records; Parent grid refreshed after DialogResult.OK, and Cancel persists nothing.
Module 5: Validation, ErrorProvider, and User Feedback
Module 5 of Data Binding with EF Core — wire entities to the UI with two-way binding, validation and async loads. Read the lesson guide and the lab / exam guide, watch the validation feedback walkthrough, pass the knowledge check, then complete the hands-on lab in the Support Desk Data Console.
- ReadingLesson Guide · 14 min
Three layers of validation, DataAnnotations on edit models, a TicketValidator service returning field and summary messages, ErrorProvider and summary feedback in Wisej.NET, and DbUpdateException as the final safety layer. What this means for a Wisej.NET developer working with real databases — and how to read this module.
- ReadingLab / Exam Guide · 10 min
What you'll build in the hands-on lab, the suggested approach, and the required deliverables.
- Video lessonValidate before you save: ErrorProvider and summaries · 14 min
Validate before you save: ErrorProvider and summaries — a guided Module 5 walkthrough, built step by step in the Support Desk Data Console. Runs right here in the player.
Narration transcript
Add validation before the ticket editor reaches the database. Users need an explanation they can act on, while the server still needs final consistency checks. This module connects model rules, field feedback, and database failure handling into one understandable save experience.
Keep all three validation layers because they protect different boundaries. Interface checks provide immediate guidance, domain rules apply outside this form too, and database constraints protect final consistency. Passing the first layer does not remove the need for the others.
Do not assume SaveChangesAsync runs the edit model’s annotations. The Required attribute helps describe mapping on an entity, but the input model needs an explicit validation call. TryValidateObject is the step that turns those declared rules into actual checks.
TicketValidator returns field names and messages after running annotations and the closed-ticket rule. It has no dependency on Wisej.NET controls, so negative cases can be tested without opening a form. The interface later decides where to display each result.
Clear old feedback, finish the edit, and validate the current model before creating a context. Route each result to its input and also to the summary. Returning at this point prevents invalid data from starting an unnecessary database operation.
Keep validation and exception handling in their proper order. Invalid input returns before saving; a concurrency exception is caught before broader database exceptions. Log technical details on the server, refresh lookups when needed, and always restore Save in finally.
Combine an empty title with a future due date on a closed ticket. Both inputs should receive useful feedback and appear in the summary, while Save remains unavailable. Correct both values to confirm that clearing errors follows the model’s current validity.
A valid input model can still fail when another agent creates the same ticket number. The unique index rejects the duplicate during saving. Translate that failure into a plain explanation for the user, while retaining the database details only in the diagnostic log.
Deliver the annotated edit model, independent validator, field feedback, and summary together. Add the duplicate-number translation and keep Save disabled for invalid input. The five negative tests should exercise the rules directly, proving they do not depend on a visible form.
- ReadingAI Coding Exercise · 20 min
Build this module's SupportDesk sample with ChatGPT or Claude from a ready-made prompt that points the model at this module's specification, then review, run and extend what it gives you — including against our own reference build on GitHub.
- Knowledge checkModule 5 Knowledge Check · 10 min · Pass mark 80%
- Hands-on labLab — Validation and Friendly Errors · 45 min
Objective: Add validation to the Support Desk ticket editor: DataAnnotations on TicketEditModel, a TicketValidator that returns field-level and summary errors, an ErrorProvider cleared before each run and set for Title, Customer, Category and DueDate, a summary label for cross-field rules, Save disabled while the model is invalid, a DbUpdateException handler that shows a friendly message for a duplicate ticket number, and at least five negative test cases. Deliverables: DataAnnotations on TicketEditModel and a TicketValidator returning field-level and summary errors; ErrorProvider cleared before each run and set for Title, Customer, Category and DueDate; Summary label for cross-field rules and Save disabled while invalid; DbUpdateException handled with a friendly message for a duplicate ticket number; At least five negative test cases.
Module 6: Async Loads, Related Data, Filtering, and Performance
Module 6 of Data Binding with EF Core — wire entities to the UI with two-way binding, validation and async loads. Read the lesson guide and the lab / exam guide, watch the slow-to-paged grid walkthrough, pass the knowledge check, then complete the hands-on lab in Support Desk Data Console.
- ReadingLesson Guide · 14 min
The related-data decision table (projection, Include, filtered Include, explicit loading, no lazy loading in grids), tracking versus no-tracking, paging and indexed filters, async coordination with loading states and background tasks, and measuring before optimising. What this means for a Wisej.NET developer working with real databases — and how to read this module.
- ReadingLab / Exam Guide · 10 min
What you'll build in the hands-on lab, the suggested approach, and the required deliverables.
- Video lessonFrom a slow grid to a paged, projected one · 14 min
From a slow grid to a paged, projected one — a guided Module 6 walkthrough, built step by step in Support Desk Data Console. Runs right here in the player.
Narration transcript
Use the slow ticket browser to measure what the database actually does. The goal is a projected, paged query with evidence from the log. Comparing the same search before and after shows whether the improvement comes from less work rather than a visual impression.
Cell formatting looks harmless until reading a navigation property triggers lazy loading. The initial ticket query is followed by related-data queries for each row. Count those statements to expose why displaying fifty rows can produce one hundred fifty-one database commands.
Choose related-data loading according to the result you need. Projection fits a flat display model; Include fits a controlled aggregate, with filtering or explicit loading where appropriate. Avoid lazy navigation access in the grid because its database cost is hidden in presentation code.
Use tracking when the editor will save the same entity instances. Read-only lists, lookups, exports, and dashboards generally do not need it. Identity resolution is a separate choice for a read-only graph that still needs one instance for each repeated entity.
Filter on indexed columns, count the matches, and retrieve a page of fifty projected list items. Selecting related names in the query lets the database join them once. Formatting the returned rows then uses available values instead of causing additional database reads.
Enable command logging in development before choosing an optimization. Examine command counts and durations to locate the bottleneck. Compiled queries, pooling, split queries, or raw database statements should address a measured need, not add complexity before the ordinary query is understood.
Compare the recorded searches: one hundred fifty-one queries become two, with the total count still present. The measured duration drops to thirty-eight milliseconds. Search and paging remain disabled during loading, so the faster database path also preserves coordinated interface behavior.
Await one operation before starting another on the same context. For longer background work, create the context inside Application.StartTask and report progress through Application.Update. Keeping ownership local to the task avoids sharing a context across simultaneous interface and background operations.
Record the original commands and duration, then replace the grid query with a no-tracking projection and fifty-row pages. Remove lazy navigation reads from presentation code. Your before-and-after note should connect the measured improvement to the database work that was eliminated.
- ReadingAI Coding Exercise · 20 min
Build this module's SupportDesk sample with ChatGPT or Claude from a ready-made prompt that points the model at this module's specification, then review, run and extend what it gives you — including against our own reference build on GitHub.
- Knowledge checkModule 6 Knowledge Check · 10 min · Pass mark 80%
- Hands-on labLab — Measure and Optimise the Ticket Browser · 45 min
Objective: Optimise the Support Desk ticket browser: enable EF Core logging in development, record the SQL and timing of the unoptimised search, replace entity loading with projection, add AsNoTracking to grid queries, add paging with a page size of 50, replace lazy navigation access with projection or Include, and document the measured before-and-after results in your lab notes. Deliverables: EF Core logging enabled in development with the unoptimised SQL and timing recorded; Grid query rewritten as a no-tracking projection; Paging with a page size of 50 and indexed filters; No lazy-loading N+1 behaviour left in display code; Lab notes documenting the measured before-and-after improvement.
Module 7: Concurrency, Transactions, Deployment, Diagnostics, and Capstone
Module 7 of Data Binding with EF Core — wire entities to the UI with two-way binding, validation and async loads. Read the lesson guide and the lab / exam guide, watch the conflict-resolution walkthrough, pass the knowledge check, then complete the hands-on lab in the Support Desk Data Console.
- ReadingLesson Guide · 14 min
Optimistic concurrency with RowVersion and DbUpdateConcurrencyException, a conflict dialog with reload, overwrite and merge, transactions and execution strategies, environment-specific configuration and logging, a testing strategy, and the Support Desk capstone. What this means for a Wisej.NET developer working with real databases — and how to read this module.
- ReadingLab / Exam Guide · 10 min
What you'll build in the hands-on lab, the suggested approach, and the required deliverables.
- Video lessonTwo users, one ticket: resolving the conflict · 14 min
Two users, one ticket: resolving the conflict — a guided Module 7 walkthrough, built step by step in the Support Desk Data Console. Runs right here in the player.
Narration transcript
Finish the Support Desk console by protecting edits made in different sessions. Two operators can open the same ticket, so a successful save must not silently erase a change made since the editor loaded. The capstone connects that protection to deployment and diagnostics.
Dana closes the ticket while Priya still has an older edit open. Saving Priya’s priority change without checking the original version could restore the old status. RowVersion detects that the record changed, turning a silent overwrite into an explicit conflict.
Carry the version the user actually saw in TicketEditModel. When saving with a freshly loaded entity, assign that carried version as the original value. Otherwise the context would compare against its new read, missing the changes made while the user was editing.
After restoring the original version, catch the concurrency exception and inspect each affected entry. Read the current database values to build the conflict list; a missing database row means deletion. Compare differing properties so the dialog can explain the actual collision.
Present the conflict using field names and the user, database, and original values. Reload accepts current database data; overwrite requires policy permission, while merging decides per field. After resolution, refresh the grid so the surrounding screen agrees with the chosen result.
One SaveChangesAsync already provides a transaction for its changes. Use an explicit transaction when several operations must succeed together. With retry enabled, place the entire unit inside the execution strategy so a retry repeats the complete transaction rather than an isolated fragment.
Keep production connection secrets outside source code and deploy reviewed repeatable migrations during release. Disable sensitive-data logging outside development. Test services independently of the interface, using a relational database where the behavior under test depends on relational rules.
Run the two-session collision: Dana saves first, then Priya sees the conflicting status and priority beside the database values. Choosing Reload updates the editor’s version and refreshes the grid. The visible result demonstrates that the stale save was stopped rather than silently accepted.
Review the console as one connected system: projected browser, lookup loading, edit model, feedback, guards, and version checking. The migration plan and architecture note explain how it remains maintainable. The assessment rewards architecture, binding, and Entity Framework correctness together.
Submit a reproducible two-session conflict with the original version carried into saving and a clear resolution dialog. Include deployment notes, the reviewed migration script, and safe logging settings. The capstone review should be able to repeat the conflict and verify its resolution.
- ReadingAI Coding Exercise · 20 min
Build this module's SupportDesk sample with ChatGPT or Claude from a ready-made prompt that points the model at this module's specification, then review, run and extend what it gives you — including against our own reference build on GitHub.
- Knowledge checkModule 7 Knowledge Check · 10 min · Pass mark 80%
- Hands-on labLab — Concurrency and Capstone · 45 min
Objective: Make the Support Desk Data Console safe for multiple users: add RowVersion to the edit model and its hidden state, set OriginalValue before saving an existing entity, reproduce a conflict by editing the same ticket in two browser sessions, catch DbUpdateConcurrencyException, build a conflict list of proposed and database values, add Reload and Overwrite paths according to policy, generate an idempotent SQL migration script with deployment notes and environment-specific connection strings, keep sensitive-data logging off outside development, then complete the capstone review. Deliverables: RowVersion carried in the edit model and set as OriginalValue before saving; Reproducible concurrency conflict caught as DbUpdateConcurrencyException; Conflict dialog listing proposed and database values with Reload and Overwrite paths; Idempotent SQL migration script with deployment notes and environment-specific connection strings; Sensitive-data logging disabled outside development and the capstone review completed.