.= 'tag.htm'; break; case 'flag': $pre .= $default_pre .= 'flag.htm'; break; case 'my': $pre .= $default_pre .= 'my.htm'; break; case 'my_password': $pre .= $default_pre .= 'my_password.htm'; break; case 'my_bind': $pre .= $default_pre .= 'my_bind.htm'; break; case 'my_avatar': $pre .= $default_pre .= 'my_avatar.htm'; break; case 'home_article': $pre .= $default_pre .= 'home_article.htm'; break; case 'home_comment': $pre .= $default_pre .= 'home_comment.htm'; break; case 'user': $pre .= $default_pre .= 'user.htm'; break; case 'user_login': $pre .= $default_pre .= 'user_login.htm'; break; case 'user_create': $pre .= $default_pre .= 'user_create.htm'; break; case 'user_resetpw': $pre .= $default_pre .= 'user_resetpw.htm'; break; case 'user_resetpw_complete': $pre .= $default_pre .= 'user_resetpw_complete.htm'; break; case 'user_comment': $pre .= $default_pre .= 'user_comment.htm'; break; case 'single_page': $pre .= $default_pre .= 'single_page.htm'; break; case 'search': $pre .= $default_pre .= 'search.htm'; break; case 'operate_sticky': $pre .= $default_pre .= 'operate_sticky.htm'; break; case 'operate_close': $pre .= $default_pre .= 'operate_close.htm'; break; case 'operate_delete': $pre .= $default_pre .= 'operate_delete.htm'; break; case 'operate_move': $pre .= $default_pre .= 'operate_move.htm'; break; case '404': $pre .= $default_pre .= '404.htm'; break; case 'read_404': $pre .= $default_pre .= 'read_404.htm'; break; case 'list_404': $pre .= $default_pre .= 'list_404.htm'; break; default: $pre .= $default_pre .= theme_mode_pre(); break; } if ($config['theme']) { $conffile = APP_PATH . 'view/template/' . $config['theme'] . '/conf.json'; $json = is_file($conffile) ? xn_json_decode(file_get_contents($conffile)) : array(); } !empty($json['installed']) and $path_file = APP_PATH . 'view/template/' . $config['theme'] . '/htm/' . ($id ? $id . '_' : '') . $pre; (empty($path_file) || !is_file($path_file)) and $path_file = APP_PATH . 'view/template/' . $config['theme'] . '/htm/' . $pre; if (!empty($config['theme_child']) && is_array($config['theme_child'])) { foreach ($config['theme_child'] as $theme) { if (empty($theme) || is_array($theme)) continue; $path_file = APP_PATH . 'view/template/' . $theme . '/htm/' . ($id ? $id . '_' : '') . $pre; !is_file($path_file) and $path_file = APP_PATH . 'view/template/' . $theme . '/htm/' . $pre; } } !is_file($path_file) and $path_file = APP_PATH . ($dir ? 'plugin/' . $dir . '/view/htm/' : 'view/htm/') . $default_pre; return $path_file; } function theme_mode_pre($type = 0) { global $config; $mode = $config['setting']['website_mode']; $pre = ''; if (1 == $mode) { $pre .= 2 == $type ? 'portal_category.htm' : 'portal.htm'; } elseif (2 == $mode) { $pre .= 2 == $type ? 'flat_category.htm' : 'flat.htm'; } else { $pre .= 2 == $type ? 'index_category.htm' : 'index.htm'; } return $pre; } ?>c# - How to replicate SQL queries generated by the ORM nHibernate? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How to replicate SQL queries generated by the ORM nHibernate? - Stack Overflow

programmeradmin1浏览0评论

In a C# application, using nHibernate & fluent nHibernate, we're looking to capture certain INSERT, UPDATE, DELETE queries performed on a Sqlite database in order to replicate them. We'd like to replicate only certain queries that affect certain entity types.

After several searches and tests, we haven't found a way to do this.
We have developed a solution using an Interceptor as well as Listeners, but neither solution seems to work. An Interceptor can be used to retrieve the generated SQL, but we lack context for its application. Listeners (IPostInsertEventListener, IPostUpdateEventListener, IPostDeleteEventListener) have many more parameters, but we can't find a way to retrieve the raw SQL query.

Using Interceptor by overriding OnPrepareStatement(SqlString sql) is the simplest method, but it lacks the context of the entity on which the operation has been performed.

public override SqlString OnPrepareStatement(SqlString sql)
{
    // Only raw SQL
    Console.WriteLine(sql);
    return base.OnPrepareStatement(sql);
}

And by using Listeners, we get a lot more information, we can understand the context and the entity that is being modified, but we can't find the SQL generated.

    public class QueryListener(Configuration cfg) : IPreUpdateEventListener, IPostUpdateEventListener, IPreInsertEventListener, IPostInsertEventListener
    {
        public void Register()
        {
            cfg.EventListeners.PreUpdateEventListeners = [.. cfg.EventListeners.PreUpdateEventListeners, this];
            cfg.EventListeners.PostUpdateEventListeners = [.. cfg.EventListeners.PostUpdateEventListeners, this];
            cfg.EventListeners.PreInsertEventListeners = [.. cfg.EventListeners.PreInsertEventListeners, this];
            cfg.EventListeners.PostInsertEventListeners = [.. cfg.EventListeners.PostInsertEventListeners, this];
        }

        public void OnPostUpdate(PostUpdateEvent @event)
        {
            // Capture SQL here ?
        }

        public bool OnPreUpdate(PreUpdateEvent @event)
        {
            // Capture SQL here ?
            return false;
        }

        public bool OnPreInsert(PreInsertEvent @event)
        {
            // Capture SQL here ?
            return false;
        }

        public void OnPostInsert(PostInsertEvent @event)
        {
            // Capture SQL here ?
        }

        #region Async methods
        public Task OnPostUpdateAsync(PostUpdateEvent @event, CancellationToken cancellationToken)
        {
            OnPostUpdate(@event);
            return Task.CompletedTask;
        }

        public Task<bool> OnPreUpdateAsync(PreUpdateEvent @event, CancellationToken cancellationToken)
        {
            return Task.FromResult(OnPreUpdate(@event));
        }

        public Task<bool> OnPreInsertAsync(PreInsertEvent @event, CancellationToken cancellationToken)
        {
            return Task.FromResult(OnPreInsert(@event));
        }

        public Task OnPostInsertAsync(PostInsertEvent @event, CancellationToken cancellationToken)
        {
            OnPostInsert(@event);
            return Task.CompletedTask;
        } 
        #endregion
    }

Ideally, we'd like to reproduce the delta mechanism proposed by SyncFramework ().

Thanks in advance for your help!

In a C# application, using nHibernate & fluent nHibernate, we're looking to capture certain INSERT, UPDATE, DELETE queries performed on a Sqlite database in order to replicate them. We'd like to replicate only certain queries that affect certain entity types.

After several searches and tests, we haven't found a way to do this.
We have developed a solution using an Interceptor as well as Listeners, but neither solution seems to work. An Interceptor can be used to retrieve the generated SQL, but we lack context for its application. Listeners (IPostInsertEventListener, IPostUpdateEventListener, IPostDeleteEventListener) have many more parameters, but we can't find a way to retrieve the raw SQL query.

Using Interceptor by overriding OnPrepareStatement(SqlString sql) is the simplest method, but it lacks the context of the entity on which the operation has been performed.

public override SqlString OnPrepareStatement(SqlString sql)
{
    // Only raw SQL
    Console.WriteLine(sql);
    return base.OnPrepareStatement(sql);
}

And by using Listeners, we get a lot more information, we can understand the context and the entity that is being modified, but we can't find the SQL generated.

    public class QueryListener(Configuration cfg) : IPreUpdateEventListener, IPostUpdateEventListener, IPreInsertEventListener, IPostInsertEventListener
    {
        public void Register()
        {
            cfg.EventListeners.PreUpdateEventListeners = [.. cfg.EventListeners.PreUpdateEventListeners, this];
            cfg.EventListeners.PostUpdateEventListeners = [.. cfg.EventListeners.PostUpdateEventListeners, this];
            cfg.EventListeners.PreInsertEventListeners = [.. cfg.EventListeners.PreInsertEventListeners, this];
            cfg.EventListeners.PostInsertEventListeners = [.. cfg.EventListeners.PostInsertEventListeners, this];
        }

        public void OnPostUpdate(PostUpdateEvent @event)
        {
            // Capture SQL here ?
        }

        public bool OnPreUpdate(PreUpdateEvent @event)
        {
            // Capture SQL here ?
            return false;
        }

        public bool OnPreInsert(PreInsertEvent @event)
        {
            // Capture SQL here ?
            return false;
        }

        public void OnPostInsert(PostInsertEvent @event)
        {
            // Capture SQL here ?
        }

        #region Async methods
        public Task OnPostUpdateAsync(PostUpdateEvent @event, CancellationToken cancellationToken)
        {
            OnPostUpdate(@event);
            return Task.CompletedTask;
        }

        public Task<bool> OnPreUpdateAsync(PreUpdateEvent @event, CancellationToken cancellationToken)
        {
            return Task.FromResult(OnPreUpdate(@event));
        }

        public Task<bool> OnPreInsertAsync(PreInsertEvent @event, CancellationToken cancellationToken)
        {
            return Task.FromResult(OnPreInsert(@event));
        }

        public Task OnPostInsertAsync(PostInsertEvent @event, CancellationToken cancellationToken)
        {
            OnPostInsert(@event);
            return Task.CompletedTask;
        } 
        #endregion
    }

Ideally, we'd like to reproduce the delta mechanism proposed by SyncFramework (https://github/egarim/SyncFramework/tree/main).

Thanks in advance for your help!

Share Improve this question edited Jan 30 at 13:48 Panagiotis Kanavos 132k16 gold badges203 silver badges265 bronze badges asked Jan 30 at 13:39 pp-mluthipp-mluthi 115 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

keeping some form of context within your interceptor? If the order of the method calls is compatible and you set the context, it will be available when the OnPrepareStatement method is called.

Something like:

public class SqlLoggingInterceptor : EmptyInterceptor {
    private object _currentEntity;

    public override bool OnSave(object entity, 
                                object id, 
                                object[] state,
                                string[] propertyNames,
                                IType[] types)
    {
        _currentEntity = entity;

        return true;
    }

    public override SqlString OnPrepareStatement(SqlString sql)
    {
        // Use _currentEntity here

        return base.OnPrepareStatement(sql);
    }
    
}

If I've read the documentation correctly, interceptors are scoped per-session, so there's some potential issues with keeping track of the correct context, but it could be worth exploring.

The stumbling block may be that the OnPrepareStatement method is called before you can set the context.

发布评论

评论列表(0)

  1. 暂无评论