Bagaimana saya bisa menggunakan NOLOCKfungsi pada Entity Framework? Apakah XML satu-satunya cara untuk melakukan ini?
Bagaimana saya bisa menggunakan NOLOCKfungsi pada Entity Framework? Apakah XML satu-satunya cara untuk melakukan ini?
Jawaban:
Tidak, tetapi Anda dapat memulai transaksi dan mengatur level isolasi untuk membaca tanpa komitmen . Ini pada dasarnya melakukan hal yang sama dengan NOLOCK, tetapi alih-alih melakukannya berdasarkan tabel, itu akan melakukannya untuk semua yang ada dalam ruang lingkup transaksi.
Jika itu terdengar seperti yang Anda inginkan, inilah cara Anda dapat melakukannya ...
//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();
}
Metode penyuluhan dapat membuat ini lebih mudah
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;
}
}
Jika Anda memerlukan sesuatu yang luas, cara terbaik yang kami temukan yang tidak terlalu mengganggu daripada benar-benar memulai transaksi setiap kali, adalah dengan hanya mengatur tingkat isolasi transaksi default pada koneksi Anda setelah Anda membuat konteks objek Anda dengan menjalankan perintah sederhana ini:
this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx
Dengan teknik ini, kami dapat membuat penyedia EF sederhana yang menciptakan konteks untuk kami dan benar-benar menjalankan perintah ini setiap kali untuk semua konteks kami sehingga kami selalu "membaca tanpa komitmen" secara default.
Transactions running at the READ UNCOMMITTED level do not issue shared locks. Ini menyiratkan bahwa Anda harus menjalankan transaksi untuk mendapatkan manfaat. (diambil dari msdn.microsoft.com/en-gb/library/ms173763.aspx ). Pendekatan Anda mungkin tidak terlalu mengganggu, tetapi tidak akan mencapai apa pun jika Anda tidak menggunakan transaksi.
SET TRANSACTION ISOLATION LEVEL...perintah mempengaruhi properti koneksi-tingkat dan karenanya mempengaruhi semua pernyataan SQL yang dibuat dari saat itu (untuk koneksi YANG), kecuali diganti dengan petunjuk query. Perilaku ini telah ada sejak setidaknya SQL Server 2000, dan kemungkinan sebelumnya.
CREATE TABLE ##Test(Col1 INT); BEGIN TRAN; SELECT * FROM ##Test WITH (TABLOCK, XLOCK);. Buka permintaan lain (# 2) dan menjalankan: SELECT * FROM ##Test;. SELECT tidak akan kembali karena diblokir oleh transaksi yang masih terbuka di tab # 1 yang menggunakan kunci eksklusif. Batalkan SELECT di # 2. Jalankan SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDsekali di tab # 2. Jalankan SELECT lagi di tab # 2 dan itu akan kembali. Pastikan dijalankan ROLLBACKdi tab # 1.
Meskipun saya benar-benar setuju bahwa menggunakan tingkat isolasi transaksi Read Uncommitted adalah pilihan terbaik, tetapi beberapa kali Anda dipaksa untuk menggunakan petunjuk NOLOCK atas permintaan manajer atau klien dan tidak ada alasan untuk menentang hal ini diterima.
Dengan Entity Framework 6 Anda dapat menerapkan DbCommandInterceptor sendiri seperti ini:
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)");
}
}
}
Dengan kelas ini tersedia, Anda dapat menerapkannya pada awal aplikasi:
DbInterception.Add(new NoLockInterceptor());
Dan matikan menambahkan NOLOCKpetunjuk ke permintaan untuk thread saat ini:
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); }
Meningkatkan jawaban yang diterima Dokter Jones dan menggunakan PostSharp ;
Pertama " 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();
}
}
}
}
Maka kapan pun Anda membutuhkannya,
[ReadUncommitedTransactionScope()]
public static SomeEntities[] GetSomeEntities()
{
using (var context = new MyEntityConnection())
{
//any reads we do here will also read uncomitted data
//...
//...
}
}
Mampu menambahkan "NOLOCK" dengan interceptor juga bagus tetapi tidak akan berfungsi saat menghubungkan ke sistem database lain seperti Oracle.
Untuk mengatasinya, saya membuat tampilan pada database dan menerapkan NOLOCK pada permintaan tampilan. Saya kemudian memperlakukan tampilan sebagai tabel dalam EF.
Dengan diperkenalkannya EF6, Microsoft merekomendasikan untuk menggunakan metode BeginTransaction ().
Anda dapat menggunakan BeginTransaction alih-alih TransactionScope di EF6 + dan EF Core
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
}
Tidak, tidak juga - Kerangka Entitas pada dasarnya adalah lapisan yang cukup ketat di atas basis data Anda yang sebenarnya. Kueri Anda diformulasikan dalam ESQL - Entity SQL - yang pertama-tama ditargetkan untuk model entitas Anda, dan karena EF mendukung banyak database backend, Anda tidak dapat benar-benar mengirim SQL "asli" langsung ke backend Anda.
Petunjuk kueri NOLOCK adalah hal khusus SQL Server dan tidak akan berfungsi pada basis data yang didukung lainnya (kecuali jika mereka juga menerapkan petunjuk yang sama - yang sangat saya ragukan).
Marc
Database.ExecuteSqlCommand()atau DbSet<T>.SqlQuery().
(NOLOCK)- lihat Kebiasaan Buruk untuk menendang - menempatkan NOLOCK di mana - mana - TIDAK DIREKOMENDASIKAN untuk menggunakan ini di mana-mana - justru sebaliknya!