Varlık Çerçevesi ve Bağlantı Havuzu Oluşturma


268

Son zamanlarda .NET 4.0 uygulamamda Entity Framework 4.0'ı kullanmaya başladım ve havuz oluşturma ile ilgili birkaç şey merak ediyorum.

  1. Bildiğim gibi bağlantı havuzu ADO.NET veri sağlayıcısı tarafından yönetilir, benim durumumda MS SQL sunucusu. Yeni bir varlıklar bağlamı ( ObjectContext), yani parametresiz başlatırken bu geçerli new MyDatabaseModelEntities()midir?

  2. A) uygulama için bir global varlıklar bağlamı oluşturmak (yani bir statik örnek) veya b) verilen her işlem / yöntem için bir varlıklar bağlamını oluşturmak ve bir usingblokla göstermek.

  3. Bilmem gereken belirli senaryolar için başka öneriler, en iyi uygulamalar veya ortak yaklaşımlar?

Yanıtlar:


369
  1. Bağlantı havuzu oluşturma işlemi diğer ADO.NET uygulamalarında olduğu gibi yapılır. Varlık bağlantısı, geleneksel bağlantı dizesiyle geleneksel veritabanı bağlantısını kullanmaya devam eder. Kullanmak istemiyorsanız bağlantı dizesinde bağlantı havuzunu kapatabileceğinize inanıyorum. ( SQL Server Bağlantı Havuzu Oluşturma (ADO.NET) hakkında daha fazla bilgi edinin )
  2. Asla küresel bağlamı kullanmayın. ObjectContext, Kimlik Haritası ve İş Birimi dahil olmak üzere çeşitli desenleri dahili olarak uygular. Genel bağlam kullanmanın etkisi, uygulama türüne göre farklıdır.
  3. Web uygulamaları için istek başına tek bir bağlam kullanın. Web servisleri için arama başına tek bir bağlam kullanın. WinForms veya WPF uygulamasında form veya sunucu başına tek bir bağlam kullanın. Bu yaklaşımın kullanılmasına izin vermeyecek bazı özel gereksinimler olabilir, ancak çoğu durumda bu yeterlidir.

WPF / WinForm uygulaması için hangi etkinin tek bir nesne bağlamına sahip olduğunu bilmek istiyorsanız bu makaleye bakın . Bu NHibernate Oturumu ile ilgili ama fikir aynı.

Düzenle:

EF kullandığınızda, varsayılan olarak her varlığı bağlam başına yalnızca bir kez yükler. İlk sorgu varlık instaransı oluşturur ve dahili olarak saklar. Aynı anahtarla varlık gerektiren sonraki sorgularda bu depolanan örnek döndürülür. Veri deposundaki değerler değiştiyse yine de ilk sorgudaki değerleri içeren varlığı alırsınız. Buna Kimlik haritası deseni denir . Nesne içeriğini varlığı yeniden yüklemeye zorlayabilirsiniz, ancak tek bir paylaşılan örneği yeniden yükler.

Varlık üzerinde yapılan değişiklikler siz SaveChangesbağlamı çağırıncaya kadar devam etmez . Birden fazla varlıkta değişiklik yapabilir ve aynı anda saklayabilirsiniz. Buna İş Birimi modeli denir . Hangi değiştirilmiş ekli varlığı kaydetmek istediğinizi seçemezsiniz.

Bu iki deseni birleştirdiğinizde bazı ilginç efektler göreceksiniz. Tüm uygulama için yalnızca bir varlık örneğiniz var. İşletmedeki herhangi bir değişiklik, değişiklikler henüz devam etmemiş (işlenmiş) olsa bile tüm başvuruyu etkiler. Çoğu zaman bu istediğiniz şey değildir. WPF uygulamasında bir düzenleme formunuz olduğunu varsayalım. Varlıkla birlikte çalışıyorsunuz ve karmaşık düzenlemeyi iptal etmeye karar veriyorsunuz (değerleri değiştirme, ilgili varlıkları ekleme, diğer ilgili varlıkları kaldırma vb.). Ancak varlık zaten paylaşılan bağlamda değiştirilmiştir. Ne yapacaksın? İpucu: Herhangi bir CancelChanges veya UndoChanges hakkında bilmiyorum ObjectContext.

Bence sunucu senaryosunu tartışmak zorunda değiliz. Tek bir varlığı birden çok HTTP isteği veya Web hizmeti çağrısı arasında paylaşmak uygulamanızı işe yaramaz hale getirir. Tüm istekler SaveChangesarasında tek bir iş birimini paylaştığınız için , herhangi bir istek yalnızca kısmi verileri başka bir istekte tetikleyebilir ve kaydedebilir. Bunun başka bir sorunu daha olacaktır - bağlam ve bağlamda varlıklar veya bağlam tarafından kullanılan bir veritabanı bağlantısı ile herhangi bir manipülasyon iş parçacığı için güvenli değildir.

Salt okunur bir uygulama için bile, küresel bir bağlam iyi bir seçim değildir, çünkü uygulamayı her sorguladığınızda muhtemelen yeni veriler istersiniz.


Cevabın için teşekkürler. Belki de tek bir küresel bağlamı kullanmanın neden kötü olduğunu açıklayabilirsiniz? Paralel erişimi kesinlikle zorlaştırıyor, ama başka ne var?
Noldorin

Tamam, şimdi çok daha net, teşekkürler. Küresel bir bağlam hiçbir zaman gerçekten uygun olmasa da, bir "düzenleme iletişim kutusu" ya da bunun için tek bir bağlam doğru yol olabilir mi? Web hizmetleri ve ASP.NET gibi diğer durumlarda, yöntemler içindeki bağlamlar yalnızca daha mantıklıdır. Doğru hakkında?
Noldorin

Tavsiyeni aldım ve singeltonu çıkardım. Şimdi başka bir hata alıyorum: stackoverflow.com/questions/14795899/…
Elad Benda

Çalışma düzeni biriminin uygulanmasının ve DbContext'in kapsüllenmesinin iş mantığı ve veritabanı işlemlerini ayırması gerektiğini anlıyorum. İş birimi modelini nasıl uygulayacağımı ve TransactionScope'u yalnızca bazı işlemler için nasıl kullanacağımı anlayamıyorum.
Rudolf Dvoracek

4
@RudolfDvoracek: Kolayca. TransactionScopeiş birimine ait değildir, iş mantığınıza aittir, çünkü mantığın kendisi işlemi tanımlar. İş birimi yalnızca neyin birlikte kalması gerektiğini tanımlarken, işlem kapsamı, iş kalıcılığı birimini aynı işlem içinde birden çok kez kullanmanızı sağlar.
Ladislav Mrnka

70

Daniel Simmons'a göre:

Her hizmet yöntemi için Using deyiminde yeni bir ObjectContext örneği oluşturun, böylece yöntem dönmeden önce atılır. Bu adım, hizmetinizin ölçeklenebilirliği için önemlidir. Veritabanı bağlantılarının hizmet çağrıları boyunca açık tutulmamasını ve belirli bir işlem tarafından kullanılan geçici durumun, işlem bittiğinde toplanan çöp olduğundan emin olur. Entity Framework, meta verileri ve uygulama etki alanında ihtiyaç duyduğu diğer bilgileri otomatik olarak önbelleğe alır ve ADO.NET veritabanı bağlantılarını havuzlar, böylece her seferinde içeriği yeniden oluşturmak hızlı bir işlemdir.

Buradaki kapsamlı makalesinden:

http://msdn.microsoft.com/en-us/magazine/ee335715.aspx

Bu tavsiyenin HTTP isteklerini de kapsadığına inanıyorum, bu yüzden ASP.NET için geçerli olacak. WPF uygulaması gibi durum bilgisi olan, yağ-istemci uygulaması "paylaşılan" bağlam için tek durum olabilir.


Teşekkürler, bu çok bilgilendirici bir teklif. Ancak, hala bir istemci WPF uygulaması veya benzeri için bile paylaşılan (genel) bir bağlamın uygun olup olmayacağını merak ediyorum. Bu durumda bile herhangi bir avantaj var mı ?
Noldorin

Bir WPF uygulamasında küresel bir bağlamın hiçbir avantajı olmayacaktır, ancak muhtemelen önemli bir zarar da olmayacaktır. Genel bir bağlam uygularsanız, yüksek istek oranlarında veritabanı bağlantılarının manuel olarak yönetilmesi (bağlantının açıkça kapatılması) gerekebilir.
Dave Swersky

1
Sağ; yani aslında birden fazla geçici bağlam kullanarak gerçekten yanlış gidemem (bağlantı havuzu olduğunu biliyorum verilen)? ... Tek bir küresel bağlam kullanıyorsanız, teoride bağlantı zaman içinde rastgele bir noktaya düşemez mi?
Noldorin

1
@Nolodrin: Bağlantının "rastgele" düşeceğini sanmıyorum ... risk, bağlantıların çok uzun süre açık tutulabilmesi ve bağlantı havuzunu doyurmasıdır.
Dave Swersky

1
ObjectContext / DbContext uygulamak IDisposable, bu nedenle en kısa sürede açık olmalı, benim görüşüme göre.
nicodemus13

12

EF6 (4,5 de) belgelerine göre: https://msdn.microsoft.com/en-us/data/hh949853#9

9.3 İstek başına bağlam

Entity Framework'ün bağlamlarının, en uygun performans deneyimini sağlamak için kısa ömürlü örnekler olarak kullanılması amaçlanmıştır . Bağlamların kısa ömürlü ve atılmaları beklenir ve bu nedenle çok hafif olması ve mümkün olduğunda meta verileri yeniden düzenlemek için uygulanmıştır. Web senaryolarında, bunu akılda tutmak ve tek bir istek süresinden daha uzun bir süre bağlamı olmamak önemlidir. Benzer şekilde, web dışı senaryolarda, Varlık Çerçevesinde farklı önbellek düzeylerini anlamanıza göre bağlam atılmalıdır. Genel olarak konuşursak, uygulamanın ömrü boyunca bağlam örneği ve iş parçacığı başına bağlamlar ve statik bağlamlardan kaçınılmalıdır.


2
Bu cevabın bir süredir geldiğini biliyorum, ama bunun bana bir ton baş ağrısından kurtardığını söylemeliyim. Oracle ile EF kullanırken "Pooled Connection" hatası almaya devam ettim ve nedenini bulamadım. Ben dbContext bir sınıf değişkeni olarak, oluşturma sırasında başlatan ayarlamıştı. Gerektiği gibi bağlam yaratmaya dönüştürmek dünyamın tüm hastalıklarını düzeltti. Teşekkür ederim!
Fletchius

1

Aşağıdaki kod, nesnemin yeni veritabanı değerleri ile yenilenmesine yardımcı oldu. Entry (object) .Reload () komutu, nesneyi veritabanı değerlerini çağırmaya zorlar

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();

ve koleksiyonlar için bu (VB kodu):CType(myContext, IObjectContextAdapter).ObjectContext.Refresh(RefreshMode.StoreWins,myCustomers)
Ivan Ferrer Villa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.