C# MVC设备配置保存问题:生成新ConfigId与递增VersionNr求助
Hey Roland, let's break down how to fix and optimize your device configuration system—sounds like you're dealing with versioning and batch config line management, which are super common gotchas. Let's start with the core issues and actionable solutions based on what you described.
1. Ensure New config_id & Proper VersionNr Increment on Save
The biggest mistake here is likely modifying existing configuration records instead of creating full new versions. You need to preserve historical configs, so every save should generate a fresh set of entries tied to a new config_id and incremented VersionNr.
Key Code Adjustment Example
Assuming your Device entity links to multiple Device_Pricelist versions, here's how to safely generate new versions:
public ActionResult Edit(int? Id) { if (Id == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var targetDevice = db.Devices.Find(Id); if (targetDevice == null) return HttpNotFound(); // Get the latest version number for the device (start at 0 if no versions exist) int latestVersion = db.Device_Pricelist .Where(dp => dp.DeviceId == Id) .Select(dp => dp.VersionNr) .DefaultIfEmpty(0) .Max(); // Fetch modified config lines from your form/view model var userModifiedLines = /* Bind from request data, e.g., using a ViewModel */; // Generate new config_id (use database auto-increment if possible, or manual max+1) int newConfigId = db.Device_Pricelist.Max(dp => dp.Config_ID) + 1; int newVersionNr = latestVersion + 1; // Create new config entries for the new version foreach (var line in userModifiedLines) { var newConfigEntry = new Device_Pricelist { Config_ID = newConfigId, DeviceId = Id.Value, VersionNr = newVersionNr, // Copy all relevant config fields from the user's input Price = line.Price, DeviceType = line.DeviceType, // ... other config properties }; db.Device_Pricelist.Add(newConfigEntry); } db.SaveChanges(); return RedirectToAction("Index"); }
2. Handle Bulk Add/Delete of Config Lines
When users add or remove lines, remember:
- Don't delete historical config lines: Instead, exclude marked-for-delete lines from the new version.
- Use a ViewModel to simplify binding: Avoid directly passing entities between your view and controller.
Example ViewModel for Clean Binding
public class DeviceConfigEditViewModel { public int DeviceId { get; set; } public List<ConfigLineViewModel> ConfigLines { get; set; } = new(); } public class ConfigLineViewModel { public int? ExistingLineId { get; set; } // Null = new line public bool IsMarkedForDelete { get; set; } // For user-deleted lines public decimal Price { get; set; } public string DeviceType { get; set; } // ... other config fields }
Updated Post Method to Handle Bulk Changes
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(DeviceConfigEditViewModel model) { if (!ModelState.IsValid) return View(model); using (var transaction = db.Database.BeginTransaction()) { try { // Re-fetch latest version inside the transaction to avoid concurrency issues int latestVersion = db.Device_Pricelist .Where(dp => dp.DeviceId == model.DeviceId) .Select(dp => dp.VersionNr) .DefaultIfEmpty(0) .Max(); int newConfigId = db.Device_Pricelist.Max(dp => dp.Config_ID) + 1; int newVersionNr = latestVersion + 1; // Only add lines that aren't marked for deletion foreach (var line in model.ConfigLines.Where(l => !l.IsMarkedForDelete)) { db.Device_Pricelist.Add(new Device_Pricelist { Config_ID = newConfigId, DeviceId = model.DeviceId, VersionNr = newVersionNr, Price = line.Price, DeviceType = line.DeviceType }); } db.SaveChanges(); transaction.Commit(); } catch (Exception ex) { transaction.Rollback(); ModelState.AddModelError("", "Another user updated this config. Please refresh and try again."); return View(model); } } return RedirectToAction("Index"); }
3. Fix Concurrency Issues for VersionNr
If multiple users edit the same device's config at once, you might get duplicate VersionNr values. The transaction above helps, but you can also add a unique constraint on (DeviceId, VersionNr) in your database to enforce version uniqueness.
4. Database Structure Optimization
For better scalability and clarity, split config metadata from line items:
-- Table to track config versions (metadata only) CREATE TABLE DeviceConfigVersions ( Config_ID INT PRIMARY KEY IDENTITY, DeviceId INT FOREIGN KEY REFERENCES Devices(Id), VersionNr INT NOT NULL, CreatedAt DATETIME DEFAULT GETDATE(), CreatedBy NVARCHAR(50), UNIQUE(DeviceId, VersionNr) -- Prevent duplicate versions per device ) -- Table for individual config lines (linked to a version) CREATE TABLE Device_Pricelist ( LineId INT PRIMARY KEY IDENTITY, Config_ID INT FOREIGN KEY REFERENCES DeviceConfigVersions(Config_ID), Price DECIMAL(18,2), DeviceType NVARCHAR(50), -- ... other config fields )
This makes it easier to query historical versions and keeps your data organized.
内容的提问来源于stack exchange,提问作者Roland_dfa

