diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Device.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Device.cs
index 603005b..b2608b2 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Device.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Device.cs
@@ -19,5 +19,8 @@ public sealed class Device
/// Schemaless per-driver-type device config (host, port, unit ID, slot, etc.).
public required string DeviceConfig { get; set; }
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/DriverInstance.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/DriverInstance.cs
index f2168a3..3453562 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/DriverInstance.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/DriverInstance.cs
@@ -45,6 +45,9 @@ public sealed class DriverInstance
///
public string? ResilienceConfig { get; set; }
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
public ServerCluster? Cluster { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Equipment.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Equipment.cs
index adc68ae..53c4bbc 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Equipment.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Equipment.cs
@@ -60,5 +60,8 @@ public sealed class Equipment
public bool Enabled { get; set; } = true;
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Namespace.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Namespace.cs
index fea7459..6e194cd 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Namespace.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Namespace.cs
@@ -26,6 +26,9 @@ public sealed class Namespace
public string? Notes { get; set; }
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
public ServerCluster? Cluster { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/NodeAcl.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/NodeAcl.cs
index 57cb906..cc9f6b6 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/NodeAcl.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/NodeAcl.cs
@@ -28,5 +28,8 @@ public sealed class NodeAcl
public string? Notes { get; set; }
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/PollGroup.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/PollGroup.cs
index 856fad2..6413706 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/PollGroup.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/PollGroup.cs
@@ -15,5 +15,8 @@ public sealed class PollGroup
public int IntervalMs { get; set; }
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Script.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Script.cs
index 67174bf..edde823 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Script.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Script.cs
@@ -34,5 +34,8 @@ public sealed class Script
/// Language — always "CSharp" today; placeholder for future engines (Python/Lua).
public string Language { get; set; } = "CSharp";
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/ScriptedAlarm.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/ScriptedAlarm.cs
index f99f4be..e540a7c 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/ScriptedAlarm.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/ScriptedAlarm.cs
@@ -55,5 +55,8 @@ public sealed class ScriptedAlarm
public bool Enabled { get; set; } = true;
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Tag.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Tag.cs
index 35f2c17..31becc8 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Tag.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/Tag.cs
@@ -43,5 +43,8 @@ public sealed class Tag
/// Register address / scaling / poll group / byte-order / etc. — schemaless per driver type.
public required string TagConfig { get; set; }
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/UnsArea.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/UnsArea.cs
index d1b0bd0..dc53073 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/UnsArea.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/UnsArea.cs
@@ -16,6 +16,9 @@ public sealed class UnsArea
public string? Notes { get; set; }
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
public ServerCluster? Cluster { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/UnsLine.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/UnsLine.cs
index 1a41b74..e7c612c 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/UnsLine.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/UnsLine.cs
@@ -17,5 +17,8 @@ public sealed class UnsLine
public string? Notes { get; set; }
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/VirtualTag.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/VirtualTag.cs
index eff66a6..dbb04be 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/VirtualTag.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Entities/VirtualTag.cs
@@ -49,5 +49,8 @@ public sealed class VirtualTag
public bool Enabled { get; set; } = true;
+ /// Optimistic concurrency token for last-write-wins detection in the v2 live-edit model.
+ public byte[] RowVersion { get; set; } = Array.Empty();
+
public ConfigGeneration? Generation { get; set; }
}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/OtOpcUaConfigDbContext.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/OtOpcUaConfigDbContext.cs
index cba2bec..cd05219 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/OtOpcUaConfigDbContext.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/OtOpcUaConfigDbContext.cs
@@ -207,6 +207,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.Kind).HasConversion().HasMaxLength(32);
e.Property(x => x.NamespaceUri).HasMaxLength(256);
e.Property(x => x.Notes).HasMaxLength(1024);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany()
.HasForeignKey(x => x.GenerationId)
@@ -239,6 +240,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.ClusterId).HasMaxLength(64);
e.Property(x => x.Name).HasMaxLength(32);
e.Property(x => x.Notes).HasMaxLength(512);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
e.HasOne(x => x.Cluster).WithMany().HasForeignKey(x => x.ClusterId).OnDelete(DeleteBehavior.Restrict);
@@ -260,6 +262,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.UnsAreaId).HasMaxLength(64);
e.Property(x => x.Name).HasMaxLength(32);
e.Property(x => x.Notes).HasMaxLength(512);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
@@ -289,6 +292,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.DriverType).HasMaxLength(32);
e.Property(x => x.DriverConfig).HasColumnType("nvarchar(max)");
e.Property(x => x.ResilienceConfig).HasColumnType("nvarchar(max)");
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
e.HasOne(x => x.Cluster).WithMany().HasForeignKey(x => x.ClusterId).OnDelete(DeleteBehavior.Restrict);
@@ -313,6 +317,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.DriverInstanceId).HasMaxLength(64);
e.Property(x => x.Name).HasMaxLength(128);
e.Property(x => x.DeviceConfig).HasColumnType("nvarchar(max)");
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
@@ -345,6 +350,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.ManufacturerUri).HasMaxLength(512);
e.Property(x => x.DeviceManualUri).HasMaxLength(512);
e.Property(x => x.EquipmentClassRef).HasMaxLength(128);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
@@ -379,6 +385,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.AccessLevel).HasConversion().HasMaxLength(16);
e.Property(x => x.PollGroupId).HasMaxLength(64);
e.Property(x => x.TagConfig).HasColumnType("nvarchar(max)");
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
@@ -409,6 +416,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.PollGroupId).HasMaxLength(64);
e.Property(x => x.DriverInstanceId).HasMaxLength(64);
e.Property(x => x.Name).HasMaxLength(128);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
@@ -431,6 +439,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.ScopeId).HasMaxLength(64);
e.Property(x => x.PermissionFlags).HasConversion();
e.Property(x => x.Notes).HasMaxLength(512);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
@@ -655,6 +664,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.SourceCode).HasColumnType("nvarchar(max)");
e.Property(x => x.SourceHash).HasMaxLength(64);
e.Property(x => x.Language).HasMaxLength(16);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
@@ -681,6 +691,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.Name).HasMaxLength(128);
e.Property(x => x.DataType).HasMaxLength(32);
e.Property(x => x.ScriptId).HasMaxLength(64);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);
@@ -708,6 +719,7 @@ public sealed class OtOpcUaConfigDbContext(DbContextOptions x.AlarmType).HasMaxLength(32);
e.Property(x => x.MessageTemplate).HasMaxLength(1024);
e.Property(x => x.PredicateScriptId).HasMaxLength(64);
+ e.Property(x => x.RowVersion).IsRowVersion();
e.HasOne(x => x.Generation).WithMany().HasForeignKey(x => x.GenerationId).OnDelete(DeleteBehavior.Restrict);