sql >> データベース >  >> RDS >> PostgreSQL

SelectForUpdateをEFCoreに実装する方法

    この作業は、SQLServerを使用している私にとってです(テストされた非同期メソッドはありません):

    まず、DbCommandInterceptor(私はHintInterceptor.csと呼びました)を作成します

    using System;
    using System.Data.Common;
    using System.Data.Entity.Infrastructure.Interception;
    using System.Text.RegularExpressions;
    
    public class HintInterceptor : DbCommandInterceptor
    {
        private static readonly Regex _tableAliasRegex = new Regex(@"(?<tableAlias>FROM +(\[.*\]\.)?(\[.*\]) AS (\[.*\])(?! WITH \(*HINT*\)))", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
    
        [ThreadStatic]
        public static string HintValue;
    
        private static string Replace(string input)
        {
            if (!String.IsNullOrWhiteSpace(HintValue))
            {
                if (!_tableAliasRegex.IsMatch(input))
                {
                    throw new InvalidProgramException("Não foi possível identificar uma tabela para ser marcada para atualização(forupdate)!", new Exception(input));
                }
                input = _tableAliasRegex.Replace(input, "${tableAlias} WITH (*HINT*)");
                input = input.Replace("*HINT*", HintValue);
            }
            HintValue = String.Empty;
            return input;
        }
    
        public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            command.CommandText = Replace(command.CommandText);
        }
    
        public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            command.CommandText = Replace(command.CommandText);
        }
    }
    

    したがって、Web.configにインターセプタークラスを登録します

    <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
    <interceptors> 
      <interceptor type="Full.Path.Of.Class.HintInterceptor, Dll.Name" />
    </interceptors>
    </entityFramework>
    

    次に、HintExtensionという静的クラスを作成します

    public static class HintExtension
    {
        public static IQueryable<T> WithHint<T>(this IQueryable<T> set, string hint) where T : class
        {
            HintInterceptor.HintValue = hint;
            return set;
        }
        public static IQueryable<T> ForUpdate<T>(this IQueryable<T> set) where T : class
        {
            return set.WithHint("UPDLOCK");
        }
    }
    

    以上です。次のようなデータベーストランザクション内で使用できます。

    using(var trans = context.Database.BeginTransaction())
    {
            var query = context.mydbset.Where(a => a.name == "asd").ForUpdate();
            // not locked yet
            var mylist = query.ToList();
            // now are locked for update
            // update the props, call saveChanges() and finally call commit ( or rollback)
            trans.Commit();
            // now are unlocked
    }
    

    英語で申し訳ありませんが、私の例がお役に立てば幸いです。



    1. テーブル名が可変であるMySQLから選択する方法

    2. WP-CLIを使用してWordPressデータベースを復元する

    3. テーブルに未使用/未選択の列が多数含まれている場合、パフォーマンスに影響しますか?

    4. MySQLデータベースのUTF-8文字列が構成変更後に混乱しました