如何检索两个 SQL Server 表的审计跟踪并将它们按正确的顺序放回?

发布于 2024-10-31 08:04:03 字数 3136 浏览 0 评论 0原文

背景上下文:


我有一个名为Project的数据库表和一个名为ProjectHistory的表,具有相同的架构。我正在使用 nhibernate,所以我还有一个名为 Project 的域对象和一个名为 ProjectHistory 的域对象(源自 Project)。

目标


My goal is to retrieve data across these tables and put them back in order as the events that happened and have C# code output a typical audit trail screen of last n number of changes

详细信息


Both tables have the following fields and data types

  • Id -(int )- Project 中的主键,注意:历史表中没有 PK
  • LastUpdated (datetime)
  • Name (varchar)
  • Description (varchar)
  • Timestamp (时间戳)

Projecthistory 的目标 表的问题是,每当我对 Project 表进行更新时,ProjectHistory 表就会插入包含旧记录的新行,以便我可以进行全面审核踪迹。

我通过使用此触发器来实现此目的:

 ALTER TRIGGER ProjectTrigger
 ON Project
 AFTER UPDATE
 AS
    SET NOCOUNT ON

    insert into ProjectHistory
    select * from deleted

我的问题是,我现在需要一些 C# 代码来整理审核历史记录,其中用户选择最近的 n 个事件。

示例:


Here is an example of events:

  1. 1 月 10 日 - 创建项目 1(尚未在历史记录中)
  2. 1 月 11 日 - 创建项目 2
  3. 1 月 15 日 - 编辑项目 2(将条目放入项目 2 的历史表中,最后更新日期为 1 月 11 日)
  4. 1 月 25 日 - 编辑项目 1(将在项目 1 的历史表中添加 1 月 10 日日期的条目)

因此,正如您所看到的,如果我按历史表中的 LastUpdated 字段降序排序,则将事件 4 的结果放在事件 4 之前来自事件 3 的结果,该事件发生故障。

代码


我已尝试使用以下代码来尝试将它们组合在一起,但我将在下面解释该缺陷:

   public IEnumerable<Project> GetHistory<Project, ProjectHistory>(int numberOfChanges)
    {
        IEnumerable<Project> current;
        IEnumerable<Project> history;
            current = Session.Query<Project>()
                .OrderByDescending(r => r.LastUpdated)
                .Take(numberOfChanges);

             history = Session.Query<ProjectHistory>()
            .OrderByDescending(r => r.LastUpdated).Cast<Project>();

            IEnumerable<Project> all = current.Concat(history);
            return all.OrderByDescending(r => r.Id).ThenByDescending(r => r.LastUpdated);
        }
    } 

我对上述代码的主要问题是:

  1. 历史记录中的LastUpdated时间将反映上一个项目更新的LastUpdated时间,因此我无法排序desc 历史表中的该字段并假设我将获得正确的事件降序排列。

    1. 我可以使用 timestamp 字段进行排序(因为这是输入记录的实际时间),但您似乎无法使用 C# nhibernate 对该字段进行排序,因为该字段只是一个二进制 (8),因此它会转换为 C# 中的 byte[],不支持 IComparable。
  2. 我可以在项目表上使用lastUpdated字段,因为按lastupdate字段排序将使我按顺序获得最新的事件。我想过仅循环 project 表,然后对每个项目进行单独的查询以获取最新的历史项目,但这不支持对同一项目 ID 进行多次更改的情况。问题是我无法找到以正确顺序获取数据的方法。

我的主要观点是,我想完成我认为非常通用的事情,必须已经解决,所以我必须只是缺少这里的基本模式。

我已经有了可以将一个 Project 对象与另一个 project 对象进行比较并返回字段差异(效果完美)的代码,但我只需要一个关于弄清楚如何得到的建议这些数据以正确的顺序跨这些表从数据库中出来(来自我的查询或事后代码),这样我就可以显示“最后n个更改”,然后使用我的逻辑来显示每个更改的字段差异。

Background Context:


i have a database table called Project and a table called ProjectHistory with the same schema. I am using nhibernate so i also have a domain object called Project and a domain object called ProjectHistory (which derived from Project).

Goal


My goal is to retrieve data across these tables and put them back in order as the events that happened and have C# code output a typical audit trail screen of last n number of changes

Details


Both tables have the following fields and data types

  • Id -(int )- primary key in Project, NOTE: no PK in the history table
  • LastUpdated (datetime)
  • Name (varchar)
  • Description (varchar)
  • Timestamp (timestamp)

the goal of the Projecthistory table is that whenever i do an update to the Project table, the ProjectHistory table get inserted a new row with the old record so i can have a full audit trail.

I accomplish this through using this trigger:

 ALTER TRIGGER ProjectTrigger
 ON Project
 AFTER UPDATE
 AS
    SET NOCOUNT ON

    insert into ProjectHistory
    select * from deleted

My issue is that i now need some C# code to put together an audit history where a user select the most recent n number of events.

Example:


Here is an example of events:

  1. On Jan 10 - create project 1 (nothing in history yet)
  2. On Jan 11 - create project 2
  3. On Jan 15 - edit project 2 ( will put entry in history table of project 2 with Jan 11 date as lastupdated by)
  4. On Jan 25 - edit project 1 (will put entry in history table of project 1 with Jan 10 date on it)

so, as you can see if i sorted descending by lastupdated field in the history table, it was put the result from event 4 before the result from event 3 which is out of order.

Code


I have tried the following code to try to put them together but I will explain the flaw below:

   public IEnumerable<Project> GetHistory<Project, ProjectHistory>(int numberOfChanges)
    {
        IEnumerable<Project> current;
        IEnumerable<Project> history;
            current = Session.Query<Project>()
                .OrderByDescending(r => r.LastUpdated)
                .Take(numberOfChanges);

             history = Session.Query<ProjectHistory>()
            .OrderByDescending(r => r.LastUpdated).Cast<Project>();

            IEnumerable<Project> all = current.Concat(history);
            return all.OrderByDescending(r => r.Id).ThenByDescending(r => r.LastUpdated);
        }
    } 

My main issues with the above code are:

  1. The LastUpdated time on the history records are going to reflect the LastUpdated time of the previous Project update so i can't sort desc on that field in the history table and assume i will get a correct descending order of events.

    1. I could use the timestamp field for sorting (as that was the actual time that the record was entered) but it doesn't seem like you can sort on that field using C# nhibernate because that field is just a binary(8) so it translates to a byte[] in C# which doesn't support IComparable.
  2. I can use lastUpdated field on the Project table because sorting by lastupdate field will get me the latest recent events in order. I thought of looping through just the project table and then doing a separate query per each project to grab the latest history project but them this doesn't support a case where multiple changes to the same project id occurred. The issue is i can't figure out a way to get the data in the correct order.

My main point is that I want to accomplish what I think is a pretty generic thing that must be solved already so i must be just missing the basic pattern here.

I already have code that can compare one Project object with another project object and return the field diffs (which works perfect) but I just need a suggestion on figuring out how i get this data out of the database across these tables in the right order (either from my query or code after the fact) so I can show "the last n number of changes" and then use my logic to show the field diff for each of those changes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

昨迟人 2024-11-07 08:04:03

这是我针对一个类似项目的解决方案。创建一个视图来联合项目和项目历史表。让 SQL Server 来完成繁重的工作。

这是一个例子:

CREATE view [dbo].[VwProjectHistory] as select
    OtherFieldName,
    LastUpdated
from
    [dbo].[Project]

union all

select
    OtherFieldName,
    LastUpdated
from
    [dbo].[ProjectHistory]

Here is my solution for one similar project. Create a view to union project and project history table. Let SQL server to do the heavy lifting.

Here is an example:

CREATE view [dbo].[VwProjectHistory] as select
    OtherFieldName,
    LastUpdated
from
    [dbo].[Project]

union all

select
    OtherFieldName,
    LastUpdated
from
    [dbo].[ProjectHistory]
猫弦 2024-11-07 08:04:03

如果我正确理解你的问题,你可以简单地对转换为长的时间戳进行排序。

// The last row in your question, 0 means start from the start of byte[]
return all.OrderByDescending(r => BitConverter.ToInt64(r.Timestamp,0));

If I've understood your question correctly you can simply sort on the timestamp converted to long.

// The last row in your question, 0 means start from the start of byte[]
return all.OrderByDescending(r => BitConverter.ToInt64(r.Timestamp,0));
空气里的味道 2024-11-07 08:04:03

选项 1
这是一个链接,允许您使用order by 子句中的时间戳。我自己没有使用过这个,所以使用时需要您自担风险。

选项 2
将自动增量字段添加到 ProjectHistory,然后您可以按项目 id 和自动增量 id 对结果进行排序。我没有太多使用强制转换操作,因此我不确定这些含义,但我确信您将在映射方面进行更多工作。

选项 3
您是否研究过NHibernate Envers,它是一个支持和审计跟踪的框架?这将是一个新的学习曲线,但从长远来看,它可能会为您节省大量工作。

Option 1:
Here's a link that allows you to use the timestamp in an order by clause. I haven't used this myself, so use at your own risk.

Option 2:
Add an auto increment field to ProjectHistory and then you can sort your results by the id of the project and then the auto-increment id. I haven't use the cast operation much, so I'm not sure of those implications, but I'm sure you'll have more work with mapping.

Option 3:
Have you investigated NHibernate Envers, which is a framework for supporting and audit trail? This will be a new learning curve, but it may save you a lot of work in the long run.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文