如何从其他模型获取数据并实现根据所选办公室自动填充墨盒信息
Great question—let's break this down into actionable steps to solve both your requirements, starting with a small model tweak that'll make your data more reliable long-term.
Step 1: Refactor Models for Better Data Integrity
Right now, your Order stores the office name as a string, which is fragile—if an office gets renamed, existing orders will show outdated names and lose their reliable link to the correct cartridge. Instead, we'll use the office's Id as a foreign key:
Office.cs (no changes needed, just for reference):
public class Office { public int Id { get; set; } public string Name { get; set; } = ""; public string Cartridge { get; set; } = ""; }
Updated Order.cs:
public class Order { public int Id { get; set; } public DateTime Created { get; set; } public int OfficeId { get; set; } // Store office ID instead of name public string Cartridge { get; set; } = ""; // Optional: Add navigation property if using EF Core for easier querying public Office? Office { get; set; } }
Step 2: Auto-Fill Cartridge on Office Selection (Create/Edit Form)
We'll use JavaScript to listen for dropdown changes and populate the cartridge field. You have two solid options here:
Option A: Client-Side (Faster, No API Call)
Pass full office data to the view, then map IDs to cartridges for instant lookup:
Update OrdersController.cs (EditOrder GET method):
[HttpGet] public IActionResult EditOrder(int? id) { var offices = _repo.GetAllOffices(); // Use Office.Id as the dropdown value, Name as the display text ViewBag.Offices = new SelectList(offices, "Id", "Name"); ViewBag.OfficeData = offices; // Send full office data to the view if (id == null) return View(new Order()); else { var order = _repo.GetOrder((int)id); return View(order); } }
Update the EditOrder View:
Add a disabled cartridge input (so users can't edit it) and the JavaScript to handle the dropdown:
@model Order <div> <form asp-controller="Orders" asp-action="EditOrder" method="post"> <input asp-for="Id" type="hidden" /> <input asp-for="Created" type="hidden" /> <div> <label>Your office</label> <select asp-for="OfficeId" asp-items="ViewBag.Offices"></select> </div> <div> <label>Cartridge</label> <input asp-for="Cartridge" type="text" disabled /> </div> <input type="submit" value="Send" /> </form> </div> <script> // Serialize office data from ViewBag into a JS object const officeData = @Html.Raw(Json.Serialize(ViewBag.OfficeData)); const cartridgeMap = {}; officeData.forEach(office => { cartridgeMap[office.id] = office.cartridge; }); // Handle dropdown changes const officeSelect = document.querySelector('#OfficeId'); const cartridgeInput = document.querySelector('#Cartridge'); officeSelect.addEventListener('change', () => { cartridgeInput.value = cartridgeMap[officeSelect.value] || ''; }); // Initialize cartridge field when editing an existing order document.addEventListener('DOMContentLoaded', () => { if (officeSelect.value) { cartridgeInput.value = cartridgeMap[officeSelect.value] || ''; } }); </script>
Option B: Server-Side API Call (For Dynamic Data)
If office data changes frequently, create an API endpoint to fetch the cartridge by office ID:
Add to OrdersController.cs:
[HttpGet("GetCartridgeByOfficeId")] public IActionResult GetCartridgeByOfficeId(int officeId) { var office = _repo.GetOffice(officeId); if (office == null) return NotFound(); return Ok(new { Cartridge = office.Cartridge }); }
Update the View's Script:
<script> const officeSelect = document.querySelector('#OfficeId'); const cartridgeInput = document.querySelector('#Cartridge'); officeSelect.addEventListener('change', async () => { const officeId = officeSelect.value; if (!officeId) { cartridgeInput.value = ''; return; } const response = await fetch(`/Orders/GetCartridgeByOfficeId?officeId=${officeId}`); if (response.ok) { const data = await response.json(); cartridgeInput.value = data.Cartridge; } }); // Initialize for existing orders document.addEventListener('DOMContentLoaded', async () => { const officeId = officeSelect.value; if (officeId) { const response = await fetch(`/Orders/GetCartridgeByOfficeId?officeId=${officeId}`); if (response.ok) { const data = await response.json(); cartridgeInput.value = data.Cartridge; } } }); </script>
Secure the Post Method:
To prevent client-side tampering, override the cartridge value from the database when saving:
[HttpPost] public async Task<IActionResult> EditOrder(Order order) { if (order.Id > 0) { var existingOrder = _repo.GetOrder(order.Id); if (existingOrder != null) { existingOrder.OfficeId = order.OfficeId; existingOrder.Cartridge = _repo.GetOffice(order.OfficeId)?.Cartridge ?? ""; _repo.UpdateOrder(existingOrder); } } else { order.Cartridge = _repo.GetOffice(order.OfficeId)?.Cartridge ?? ""; _repo.AddOrder(order); } if (await _repo.SaveChangesAsync()) return RedirectToAction("Orders"); else return View(order); }
Step 3: Show Correct Cartridge in Order List
Now that we're storing OfficeId, we have two clean ways to display the cartridge:
Option 1: Use EF Core Navigation Properties
Update your repository's GetAllOrders method to include the Office navigation property:
public IEnumerable<Order> GetAllOrders() { return _context.Orders.Include(o => o.Office).ToList(); }
Update the Orders View:
@model IEnumerable<Order> <table> <thead> <tr> <th>Created Date</th> <th>Office</th> <th>Cartridge</th> </tr> </thead> <tbody> @foreach (var order in Model) { <tr> <td>@order.Created.ToString("yyyy-MM-dd HH:mm")</td> <td>@order.Office?.Name ?? "Unknown Office"</td> <td>@order.Office?.Cartridge ?? "No Cartridge Assigned"</td> </tr> } </tbody> </table>
Option 2: Map Cartridges in the Controller (No Navigation Properties)
If you don't want to use navigation properties, fetch offices and map cartridges to orders in the controller:
public IActionResult Orders(int id) { var orders = _repo.GetAllOrders(); var officeLookup = _repo.GetAllOffices().ToDictionary(o => o.Id, o => o); foreach (var order in orders) { if (officeLookup.TryGetValue(order.OfficeId, out var office)) { order.Cartridge = office.Cartridge; } } return View(orders); }
Then your existing view code @order.Cartridge will work as expected.
Quick Tips
- Always validate that the
OfficeIdexists in the database before saving orders to avoid invalid data. - Using office IDs instead of names makes your system more robust—names can change, but IDs should remain consistent.
内容的提问来源于stack exchange,提问作者Joseph

