Seçici alanları güncelleştiriliyorken Eşzamanlılık işlenemiyor Güncelleştirme varlıklarına EF5 ve Veri İlk yaklaşımını kullanıyorum. Başka varlıklar tarafından önerilen, yalnızca Varlıklar'daki değiştirilmiş özellikleri güncellemek için önerilen yaklaşımı kullanıyorum.EF5,
Oki işte buradaki senaryo Benim denetleyici çağrım Servis ile POCO nesneleriyle hizmet alıyor ve Hizmet'ten POCO nesneleri alıyor, Hizmet katmanı, DB'den varlık almak ve DB'de güncelleştirmek için EF5'i dahili olarak kullanan Veri katmanıyla konuşuyor.
Görünüm verileri, Hizmet katmanından alınan DTO nesnesinden denetleyici tarafından yüklenir. Kullanıcı, denetleyicideki DTO nesnesine eşlenen denetleyiciye (izleme MVC'si) denetleyiciye JSON verilerini görüntüle ve geri gönder. Denetleyici, DTO nesnesi (POCO) nesnesiyle Servis katmanına çağrı yapar. Hizmet, POCO nesnesini EF varlık nesnesine eşler ve EF nesnesinden geçen Veri katmanı (yani Deposu) Güncelleştirme yöntemini çağırır. Deposu'nda varolan varlığı DB'den getir ve ApplyCurrentvaluesValues yöntemini çağır, sonra herhangi bir özellik değiştirilip değiştirilmediğini kontrol ederim. Özellikler değiştirilirse, özel mantığımı geçerli varlık ile ilişkili olmayan diğer varlıklara uygularım ve ayrıca geçerli varlığın "UpdateAdminId" & "UpdationDate" öğesini Güncelleştir. Bunu yayınla, Centext'te "SaveChanges" yöntemini çağırıyorum.
Yukarıda bahsettiğim her şey gayet iyi çalışıyor, "SaveChanges" aramasında bir ara nokta koyup, User tarafından değiştirilen bazı alanları farklı bir değere güncellemem dışında "DbUpdateConcurrencyException" EF5 tarafından atılmaz. Örnek: & koşullu Güncelleştirmeyi, ilgimin özellikleri mükemmel bir şekilde çalışacak şekilde değiştirildiğinde, özel mantığımı tetikleyebilirim. Ancak eşzamanlılık durumunda hata alamıyorum, çünkü kayıt DB arasında kayıt alma, kayıt güncelleme ve kaydetme arasında bir kayıt güncellendiğinde EF "DbUpdateConcurrencyException" u yükseltmiyor.
Gerçek senaryoda, yeni oluşturulan kampanyayı denetleyen ve bunlar için portföy oluşturan ve IsPortfolioCreated özelliğini aşağıdaki gibi işaretleyen bir çevrimdışı cron çalışması vardır; bu süre içinde kullanıcı kampanyayı düzenleyebilir ve bayrak yanlış olarak ayarlanabilir cron portföyleri yaratmış olsa bile.
Eşzamanlılık senaryosunu çoğaltmak için SaveChanges üzerinde bir kesme noktası koyarım ve aynı varlık için MS-Sql kuruluş yöneticisinden IsPortfolioCreated feild'i güncellerim, ancak Mağazadaki Veri güncellenmiş olsa bile "DbUpdateConcurrencyException" atılmaz. .
İşte başvuru için benim kod, bu (geliştirici olarak) size kadar eşzamanlılık hakkında özel bir şey eşzamanlılık sorunlarını kontrol edecek şekilde yapılandırın yapmıyor
Public bool EditGeneralSettings(CampaignDefinition campaignDefinition)
{
var success = false;
//campaignDefinition.UpdatedAdminId is updated in controller by retreiving it from RquestContext, so no its not comgin from client
var updatedAdminId = campaignDefinition.UpdatedAdminId;
var updationDate = DateTime.UtcNow;
CmsContext context = null;
GlobalMasterContext globalMasterContext = null;
try
{
context = new CmsContext(SaveTimeout);
var contextCampaign = context.CampaignDefinitions.Where(x => x.CampaignId == campaignDefinition.CampaignId).First();
//Always use this fields from Server, no matter what comes from client
campaignDefinition.CreationDate = contextCampaign.CreationDate;
campaignDefinition.UpdatedAdminId = contextCampaign.UpdatedAdminId;
campaignDefinition.UpdationDate = contextCampaign.UpdationDate;
campaignDefinition.AdminId = contextCampaign.AdminId;
campaignDefinition.AutoDecision = contextCampaign.AutoDecision;
campaignDefinition.CampaignCode = contextCampaign.CampaignCode;
campaignDefinition.IsPortfolioCreated = contextCampaign.IsPortfolioCreated;
var campaignNameChanged = contextCampaign.CampaignName != campaignDefinition.CampaignName;
// Will be used in the below if condition....
var originalSkeForwardingDomain = contextCampaign.skeForwardingDomain.ToLower();
var originalMgForwardingDomain = contextCampaign.mgForwardingDomain.ToLower();
//This also not firing concurreny exception....
var key = ((IObjectContextAdapter) context).ObjectContext.CreateEntityKey("CampaignDefinitions", campaignDefinition);
((IObjectContextAdapter)context).ObjectContext.AttachTo("CampaignDefinitions", contextCampaign);
var updated = ((IObjectContextAdapter)context).ObjectContext.ApplyCurrentValues(key.EntitySetName, campaignDefinition);
ObjectStateEntry entry = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager.GetObjectStateEntry(updated);
var modifiedProperties = entry.GetModifiedProperties();
//Even tried this , works fine but no Concurrency exception
//var entry = context.Entry(contextCampaign);
//entry.CurrentValues.SetValues(campaignDefinition);
//var modifiedProperties = entry.CurrentValues.PropertyNames.Where(propertyName => entry.Property(propertyName).IsModified).ToList();
// If any fields modified then only set Updation fields
if (modifiedProperties.Count() > 0)
{
campaignDefinition.UpdatedAdminId = updatedAdminId;
campaignDefinition.UpdationDate = updationDate;
//entry.CurrentValues.SetValues(campaignDefinition);
updated = ((IObjectContextAdapter)context).ObjectContext.ApplyCurrentValues(key.EntitySetName, campaignDefinition);
//Also perform some custom logic in other entities... Then call save changes
context.SaveChanges();
//If campaign name changed call a SP in different DB..
if (campaignNameChanged)
{
globalMasterContext = new GlobalMasterContext(SaveTimeout);
globalMasterContext.Rename_CMS_Campaign(campaignDefinition.CampaignId, updatedAdminId);
globalMasterContext.SaveChanges();
}
}
success = true;
}
catch (DbUpdateConcurrencyException ex)
{
//Code never enters here, if it does then I am planning to show the user the values from DB and ask him to retry
//In short Store Wins Strategy
//Code in this block is not complete so dont Stackies don't start commenting about this section and plague the question...
// Get the current entity values and the values in the database
var entry = ex.Entries.Single();
var currentValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
// Choose an initial set of resolved values. In this case we
// make the default be the values currently in the database.
var resolvedValues = databaseValues.Clone();
// Update the original values with the database values and
// the current values with whatever the user choose.
entry.OriginalValues.SetValues(databaseValues);
entry.CurrentValues.SetValues(resolvedValues);
}
catch (Exception ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
finally
{
if (context != null) context.Dispose();
if (globalMasterContext != null) globalMasterContext.Dispose();
}
return success;
}
Varlık bazı özellikler için [ConcurrencyCheck] özelliğine sahip mi? –
@ omar.ballerani no eşzamanlılık denetim özniteliği varlığa ait değil. Ama bence bu, aşağıdaki MSDN makalesinde anlatıldığı gibi çalışmalı. https://msdn.microsoft.com/en-in/data/jj592904.aspx – Vipresh
deneyimim için DbUpdateConcurrencyException, güncellenecek satırı bulamadığında Entity Framework tarafından atılır. Bir veya daha fazla özellik için [ConcurrencyCheck] özniteliğini eklediğinizde, ef, veritabanı için ilk yaklaşım kullandığı –