I 6.
varlık Framework bir bayt [8], kolon adı rowversion IsConcurrencyToken kullanmak mümkün araştıran biraz sonra:
[System.ComponentModel.DataAnnotations.Schema.Timestamp]
özelliği IsRowVersion()
veri açıklamalar denk
Aynı veri türünü DB2'de kullanmak istiyoruz (ki bu da veritabanında kendi kendine dönüş yapmıyor) IsRowVersion() seçeneğini kullanamıyoruz!
IsConcurrencyToken ile nasıl çalışılacağını biraz daha araştırdım.
Ben iş gibi görünüyor çözüm bulmak amacıyla aşağıdaki yaptı:
Benim Modeli:
public interface IConcurrencyEnabled
{
byte[] RowVersion { get; set; }
}
public class Product : AuditableEntity<Guid>,IProduct,IConcurrencyEnabled
{
public string Name
{
get; set;
}
public string Description
{
get; set;
}
private byte[] _rowVersion = new byte[8];
public byte[] RowVersion
{
get
{
return _rowVersion;
}
set
{
System.Array.Copy(value, _rowVersion, 8);
}
}
}
IConcurrencyEnabled özel muamele gerektiren bir rowversion sahip Varlıkları tanımlamak için kullanılır.
Ben ModelBuilder yapılandırmak için akıcı API kullandı:
public class ProductConfiguration : EntityTypeConfiguration<Product>
{
public ProductConfiguration()
{
Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(e => e.RowVersion).IsFixedLength().HasMaxLength(8).IsConcurrencyToken();
}
}
Ve sonunda base.SaveChanges çağrılmadan önce alanı güncelleştirmek için benim türetilmiş DBContext sınıfa bir yöntem eklendi:
public void OnBeforeSaveChanges(DbContext dbContext)
{
foreach (var dbEntityEntry in dbContext.ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified))
{
IConcurrencyEnabled entity = dbEntityEntry.Entity as IConcurrencyEnabled;
if (entity != null)
{
if (dbEntityEntry.State == EntityState.Added)
{
var rowversion = dbEntityEntry.Property("RowVersion");
rowversion.CurrentValue = BitConverter.GetBytes((Int64)1);
}
else if (dbEntityEntry.State == EntityState.Modified)
{
var valueBefore = new byte[8];
System.Array.Copy(dbEntityEntry.OriginalValues.GetValue<byte[]>("RowVersion"), valueBefore, 8);
var value = BitConverter.ToInt64(entity.RowVersion, 0);
if (value == Int64.MaxValue)
value = 1;
else value++;
var rowversion = dbEntityEntry.Property("RowVersion");
rowversion.CurrentValue = BitConverter.GetBytes((Int64)value);
rowversion.OriginalValue = valueBefore;//This is the magic line!!
}
}
}
}
Çoğu kişinin karşılaştığı problem, varlığın değerini ayarladıktan sonra, her zaman bir UpdateDBConcurrencyException alırız, çünkü OriginalValue değişmemiş olsa bile ...
Bunun nedeni, yalnızca geçerli bir Değer (yalnızca garip ve beklenmedik davranış) olarak ayarlanmış olmanız durumunda bir bayt [] için hem özgün hem de geçerliValue değişimidir.
Bu yüzden, orijinal dizilimi tekrar orijinal değerine döndürdüm. Bu satırları değiştirmeden önce ... Ayrıca, aynı bayt dizisine başvurmaktan kaçınmak için diziyi kopyalarım!
Dikkat: Burada rowversion değiştirmek için artan bir yaklaşım kullanıyorum, bu değeri doldurmak için kendi stratejinizi kullanmakta serbestsiniz. (Rasgele veya zaman tabanlı)
Herhangi biri? :/Plx. –
* Ürün tablosu güncellenmeyecek *. Aslında, rowversion'ı artıran bir kukla güncelleme ile (EF 6.1.3). –
Merhaba @GertArnold. Testlerimde (EF6.1.3), rowversion artırılmıyor. –