NOLOCK
Entity Framework'teki işlevi nasıl kullanabilirim ? XML bunu yapmanın tek yolu mu?
NOLOCK
Entity Framework'teki işlevi nasıl kullanabilirim ? XML bunu yapmanın tek yolu mu?
Yanıtlar:
Hayır, ancak bir işlem başlatabilir ve yalıtım düzeyini sırasız okunacak şekilde ayarlayabilirsiniz . Bu esasen NOLOCK ile aynıdır, ancak bunu tablo başına yapmak yerine, işlem kapsamındaki her şey için yapacaktır.
Bu istediğiniz gibi görünüyorsa, bunu nasıl yapabileceğiniz ...
//declare the transaction options
var transactionOptions = new System.Transactions.TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new System.Transactions.TransactionScope(
System.Transactions.TransactionScopeOption.Required,
transactionOptions)
)
//declare our context
using (var context = new MyEntityConnection())
{
//any reads we do here will also read uncomitted data
//...
//...
//don't forget to complete the transaction scope
transactionScope.Complete();
}
Uzantı yöntemleri bunu kolaylaştırabilir
public static List<T> ToListReadUncommitted<T>(this IQueryable<T> query)
{
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions() {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
List<T> toReturn = query.ToList();
scope.Complete();
return toReturn;
}
}
public static int CountReadUncommitted<T>(this IQueryable<T> query)
{
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions() {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
int toReturn = query.Count();
scope.Complete();
return toReturn;
}
}
Büyük bir şeye ihtiyacınız varsa, her seferinde bir işlem kapsamına başlamaktan daha az müdahaleci bulmanın en iyi yolu, bu basit komutu çalıştırarak nesne bağlamınızı oluşturduktan sonra bağlantınızdaki varsayılan işlem yalıtım düzeyini ayarlamaktır:
this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx
Bu teknikle, bizim için bağlamı oluşturan ve bu komutu tüm bağlamımız için her seferinde çalıştıran basit bir EF sağlayıcısı oluşturabildik, böylece her zaman varsayılan olarak "taahhüt edilmemiş olarak okuyoruz".
Transactions running at the READ UNCOMMITTED level do not issue shared locks
. Bu, avantaj elde edebilmek için bir işlem içinde çalışmanız gerektiği anlamına gelir. ( msdn.microsoft.com/en-gb/library/ms173763.aspx adresinden alınmıştır ). Yaklaşımınız daha az müdahaleci olabilir, ancak bir işlem kullanmazsanız hiçbir şey başaramaz.
SET TRANSACTION ISOLATION LEVEL...
Komutu bir bağlantı seviyesi varlıkla etkiler ve sorgu ipucu geçersiz kılınmadığı takdirde dolayısıyla (BU bağlantısı için) o andan itibaren yapılan tüm SQL ifadelerini etkiler. Bu davranış, en azından SQL Server 2000'den beri ve muhtemelen daha önce olmuştur.
CREATE TABLE ##Test(Col1 INT); BEGIN TRAN; SELECT * FROM ##Test WITH (TABLOCK, XLOCK);
. Başka bir sorgu (# 2) açın ve komut satırından: SELECT * FROM ##Test;
. SELECT, özel bir kilit kullanan sekme 1'deki hala açık işlem tarafından engellendiği için geri dönmez. SEÇİMİ # 2'den iptal edin. SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Sekme # 2'de bir kez çalıştırın . Sekme # 2'de sadece SELECT'i tekrar çalıştırdığınızda geri gelecektir. ROLLBACK
Sekme # 1'de çalıştığınızdan emin olun .
Kesinlikle Okunmamış İşlem izolasyon düzeyini kullanmanın en iyi seçim olduğunu kesinlikle kabul ettim, ancak bir süre NOLOCK ipucunu yönetici veya müşterinin isteği ile kullanmak zorunda kaldınız ve buna karşı hiçbir neden kabul edilmedi.
Entity Framework 6 ile kendi DbCommandInterceptor uygulamasını şu şekilde uygulayabilirsiniz:
public class NoLockInterceptor : DbCommandInterceptor
{
private static readonly Regex _tableAliasRegex =
new Regex(@"(?<tableAlias>AS \[Extent\d+\](?! WITH \(NOLOCK\)))",
RegexOptions.Multiline | RegexOptions.IgnoreCase);
[ThreadStatic]
public static bool SuppressNoLock;
public override void ScalarExecuting(DbCommand command,
DbCommandInterceptionContext<object> interceptionContext)
{
if (!SuppressNoLock)
{
command.CommandText =
_tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)");
}
}
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
if (!SuppressNoLock)
{
command.CommandText =
_tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)");
}
}
}
Bu sınıf hazır olduğunda, uygulama başlangıcında uygulayabilirsiniz:
DbInterception.Add(new NoLockInterceptor());
Ve NOLOCK
geçerli iş parçacığı için sorgulara ipucu eklemeyi koşullu olarak kapatın :
NoLockInterceptor.SuppressNoLock = true;
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { if (!SuppressNoLock) command.CommandText = $"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;{Environment.NewLine}{command.CommandText}"; base.ReaderExecuting(command, interceptionContext); }
Üzerinde geliştirilmesi Doktor Jones 'in kabul edilen cevap ve kullanma PostSharp ;
İlk " ReadUncommitedTransactionScopeAttribute "
[Serializable]
public class ReadUncommitedTransactionScopeAttribute : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
//declare the transaction options
var transactionOptions = new TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
//declare our context
using (var scope = new TransactionScope())
{
args.Proceed();
scope.Complete();
}
}
}
}
Sonra ne zaman ihtiyacınız olursa,
[ReadUncommitedTransactionScope()]
public static SomeEntities[] GetSomeEntities()
{
using (var context = new MyEntityConnection())
{
//any reads we do here will also read uncomitted data
//...
//...
}
}
Bir durdurucu ile "NOLOCK" ekleyebilmek de güzeldir ancak Oracle gibi diğer veritabanı sistemlerine bağlanırken çalışmaz.
Bu tur almak için veritabanında bir görünüm oluşturmak ve görünümün sorgusunda NOLOCK uygulayın. Daha sonra görüntüyü EF içinde bir tablo olarak ele alıyorum.
EF6'nın tanıtılmasıyla Microsoft, BeginTransaction () yönteminin kullanılmasını önerir.
EF6 + ve EF Core'da TransactionScope yerine BeginTransaction'ı kullanabilirsiniz
using (var ctx = new ContractDbContext())
using (var transaction = ctx.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
{
//any reads we do here will also read uncommitted data
}
Hayır, gerçekten değil - Entity Framework aslında gerçek veritabanınızın üzerinde oldukça katı bir katmandır. Sorgularınız, öncelikle varlık modelinize yönelik ESQL - Entity SQL'de formüle edilmiştir ve EF birden çok veritabanı arka ucunu desteklediğinden, gerçekten "doğal" SQL'i doğrudan arka uçlarınıza gönderemezsiniz.
NOLOCK sorgu ipucu SQL Server'a özgü bir şeydir ve desteklenen diğer veritabanlarının hiçbirinde çalışmazlar (aynı ipucunu uygulamadılarsa - kesinlikle şüpheliyim).
üzüm posası
Database.ExecuteSqlCommand()
veya kullanarak "yerel" SQL çalıştırabilirsiniz DbSet<T>.SqlQuery()
.
(NOLOCK)
zaten - bkz tekme için Kötü Alışkanlıklar - her yerde nolock koyarak - olduğu ÖNERİLMEZ her yerde bu kullanmak için - tam tersine!