سؤال

لقد تم تكليفي بتطوير حل يتتبع التغييرات في قاعدة البيانات.

للحصول على التحديثات أحتاج إلى التقاط:

  • تاريخ التحديث
  • القيمة القديمة
  • قيمة جديدة
  • الميدان متأثر
  • شخص يقوم بالتغيير
  • معرف السجل
  • سجل الجدول موجود

بالنسبة للحذف:

  • تاريخ الحذف
  • الشخص الذي يقوم بالحذف
  • تم حذف عنوان/وصف/معرف السجل.تحتوي جميع الجداول التي أتتبع التغييرات عليها على حقل عنوان أو وصف.أرغب في التقاط هذا قبل حذف السجل.
  • سجل الجدول كان في

للإدراج:

  • تاريخ الإدراج
  • شخص يقوم بالتغيير
  • معرف السجل
  • سجل الجدول موجود

لقد فكرت في عدة طرق للقيام بذلك:

  • أنا أستخدم الإجراءات المخزنة لأي تحديثات/عمليات حذف/إدراجات.سأقوم بإنشاء جدول "تتبع" عام.سيكون لديه حقول كافية لالتقاط كافة البيانات.أود بعد ذلك إضافة سطر آخر في كل عملية مخزنة لتأثير "إدراج سجل في جدول التتبع".
    • الجانب السلبي:جميع التحديثات/الحذف/الإدراجات كلها مختلطة في نفس الجدول
    • الكثير من الحقول الفارغة
    • كيف يمكنني تتبع التحديثات/الحذف/الإدراجات الدفعية؟<---- قد لا تكون هذه مشكلة.لا أفعل حقًا أي شيء كهذا في التطبيق.
    • كيف يمكنني التقاط المستخدم الذي يجري التحديث.ترى قاعدة البيانات حسابًا واحدًا فقط.
    • قم بتحرير الكثير من التعليمات البرمجية الموجودة لتحريرها.
  • وأخيرًا، يمكنني إنشاء مشغل يتم استدعاؤه بعد التحديثات/الحذف/الإدراج.العديد من الجوانب السلبية نفسها مثل الحل الأول باستثناء:سأضطر إلى تعديل أكبر قدر من التعليمات البرمجية.لست متأكدًا من كيفية تتبع التحديثات.لا يبدو أن هناك طريقة لاستخدام المشغلات لرؤية السجلات التي تم تحديثها مؤخرًا.

أنا أستخدم asp.net، C#، sql server 2005، iis6، windows 2003.ليس لدي ميزانية لذلك للأسف لا أستطيع شراء أي شيء لمساعدتي في هذا.

شكرا لإجاباتك!

هل كانت مفيدة؟

المحلول

لن يحتوي المشغل على جميع المعلومات التي تحتاجها لمجموعة من الأسباب - ولكن لا يوجد معرف مستخدم هو الفاصل.

أود أن أقول إنك على المسار الصحيح مع وجود نقطة مشتركة لإدراجها أينما تم إجراء التغيير.إذا كنت تعمل على توحيد المواصفات الخاصة بواجهاتك، فأنت في المقدمة - سيكون من الصعب التسلل إلى تغيير لم يتم تتبعه.

انظر إلى هذا على أنه يعادل مسار التدقيق في تطبيق المحاسبة - هذه هي دفتر اليومية - جدول واحد مع كل معاملة مسجلة.لن يقوموا بتنفيذ مجلات منفصلة للإيداعات والسحوبات والتعديلات، وما إلى ذلك.وهذا هو نفس المبدأ.

نصائح أخرى

أنا أكره أن أتجاهل هذه المشكلة وأعلم أنه ليس لديك ميزانية، ولكن الحل الأبسط هو الترقية إلى SQL Server 2008.لديها هذه الميزة بنيت في.أعتقد أنه ينبغي على الأقل ذكر ذلك لأي شخص آخر يصادف هذا السؤال، حتى لو لم تتمكن من استخدامه بنفسك.

(من بين إصدارات SQL 2008 القابلة للنشر، تتوفر هذه الميزة فقط في Enterprise.)

أود أن أقترح عليك استخدام عمودين في كل جدول.أسماء com.rowhistory و يتم حذف وسيكون نوع البيانات هو xml و bit.لا تقم أبدًا بحذف الصفوف، واستخدم دائمًا العلامة IsDeletedاذهب الآن مع مشغلات التحديث.سأقدم لك مثالًا لنفسه لدي هذا الجدول الواحد يسمى الصفحة

    CREATE TABLE te_Page([Id] [int] IDENTITY(1,1) NOT NULL, [Name] [varchar](200) NOT NULL, [Description] [varchar](200) NULL,[CreatedBy] [uniqueidentifier] NULL, [CreatedDate] [datetime] NOT NULL, [UpdatedBy] [uniqueidentifier] NULL, [UpdatedDate] [datetime] NULL, [IsDeleted] [bit] NULL, [RowHistory] [xml] NULL, CONSTRAINT [PK_tm_Page] PRIMARY KEY CLUSTERED ([Id] ASC )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] ) ON [PRIMARY]

الآن بعد إنشاء الجدول، كل ما عليك فعله هو نسخ ولصق الكود أدناه وتكون مهمتك قد انتهت بالنسبة لجدول الصفحة.سيبدأ في تسجيل تاريخ الصف في نفس الصف والذي يتم تحديثه مع القيم القديمة والجديدة.

                ALTER Trigger [dbo].[Trg_Te_Page]    
        On [dbo].[te_Page]                
        After Update                
        As                 
        --If @@rowcount = 0 Or Update(RowHistory)    
        --Return    

        Declare @xml NVARCHAR(MAX)     
        Declare @currentxml NVARCHAR(MAX)   
        Declare @node NVARCHAR(MAX)    
        Declare @ishistoryexists XML    

        Declare @FormLineAttributeValueId int  

        -- new Values  
        Declare @new_Name varchar(200)  
        Declare @new_Description varchar(200)  

        Declare @new_CreatedBy UNIQUEIDENTIFIER    
        Declare @new_CreatedDate DATETIME    
        Declare @new_UpdatedBy UNIQUEIDENTIFIER    
        Declare @new_UpdatedDate DATETIME    
        Declare @new_IsDeleted BIT  

        --old values  
        Declare @old_Name varchar(200)  
        Declare @old_Description varchar(200)  

        Declare @old_CreatedBy UNIQUEIDENTIFIER    
        Declare @old_CreatedDate DATETIME    
        Declare @old_UpdatedBy UNIQUEIDENTIFIER    
        Declare @old_UpdatedDate DATETIME    
        Declare @old_IsDeleted BIT  


        -- declare temp fmId  
        Declare @fmId int  
        -- declare cursor  
        DECLARE curFormId cursor   
        FOR select Id from INSERTED   
        -- open cursor       
        OPEN curFormId  
        -- fetch row  
        FETCH NEXT FROM curFormId INTO @fmId  

        WHILE @@FETCH_STATUS  = 0   
        BEGIN   

        Select   
        @FormLineAttributeValueId = Id,   
        @old_Name = Name,  
        @old_Description = [Description],  

        @old_CreatedBy = CreatedBy,    
        @old_CreatedDate =CreatedDate,  
        @old_UpdatedBy =UpdatedBy,    
        @old_UpdatedDate =UpdatedDate,  
        @old_IsDeleted  = IsDeleted,  
        @currentxml = cast(RowHistory as NVARCHAR(MAX))  
        From DELETED where Id=@fmId  



        Select      
        @new_Name = Name,  
        @new_Description = [Description],  

        @new_CreatedBy = CreatedBy,    
        @new_CreatedDate =CreatedDate,  
        @new_UpdatedBy =UpdatedBy,    
        @new_UpdatedDate =UpdatedDate,  
        @new_IsDeleted  = IsDeleted  
        From INSERTED where Id=@fmId  

        set @old_Name = Replace(@old_Name,'&','&amp;')
        set @old_Name = Replace(@old_Name,'>','&gt;')  
        set @old_Name = Replace(@old_Name,'<','&lt;')     
        set @old_Name = Replace(@old_Name,'"','&quot;')
        set @old_Name = Replace(@old_Name,'''','&apos;')          

        set @new_Name = Replace(@new_Name,'&','&amp;')      
        set @new_Name = Replace(@new_Name,'>','&gt;')  
        set @new_Name = Replace(@new_Name,'<','&lt;')     
        set @new_Name = Replace(@new_Name,'"','&quot;')
        set @new_Name = Replace(@new_Name,'''','&apos;') 

        set @old_Description = Replace(@old_Description,'&','&amp;')
        set @old_Description = Replace(@old_Description,'>','&gt;')  
        set @old_Description = Replace(@old_Description,'<','&lt;')     
        set @old_Description = Replace(@old_Description,'"','&quot;')
        set @old_Description = Replace(@old_Description,'''','&apos;')          

        set @new_Description = Replace(@new_Description,'&','&amp;')      
        set @new_Description = Replace(@new_Description,'>','&gt;')  
        set @new_Description = Replace(@new_Description,'<','&lt;')     
        set @new_Description = Replace(@new_Description,'"','&quot;')
        set @new_Description = Replace(@new_Description,'''','&apos;')   

        set @xml = ''     

        BEGIN      

        -- for Name  
        If ltrim(rtrim(IsNull(@new_Name,''))) != ltrim(rtrim(IsNull(@old_Name,'')))    
        set @xml = @xml + '<ColumnInfo ColumnName="Name" OldValue="'+ @old_Name + '" NewValue="' + @new_Name + '"/>'    

        -- for Description  
        If ltrim(rtrim(IsNull(@new_Description,''))) != ltrim(rtrim(IsNull(@old_Description,'')))    
        set @xml = @xml + '<ColumnInfo ColumnName="Description" OldValue="'+ @old_Description + '" NewValue="' + @new_Description + '"/>'    

        -- CreatedDate     
        If IsNull(@new_CreatedDate,'') != IsNull(@old_CreatedDate,'')  
        set @xml = @xml + '<ColumnInfo ColumnName="CreatedDate" OldValue="'+ cast(isnull(@old_CreatedDate,'') as varchar(100)) + '" NewValue="' + cast(isnull(@new_CreatedDate,'') as varchar(100)) + '"/>'    

        -- CreatedBy     
        If cast(IsNull(@new_CreatedBy,'00000000-0000-0000-0000-000000000000')as varchar (36)) != cast(IsNull(@old_CreatedBy,'00000000-0000-0000-0000-000000000000')as varchar(36))    
        set @xml = @xml + '<ColumnInfo ColumnName="CreatedBy" OldValue="'+ cast(IsNull(@old_CreatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36)) + '" NewValue="' + cast(isnull(@new_CreatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36))+
        '"/>'    

        -- UpdatedDate       
        If IsNull(@new_UpdatedDate,'') != IsNull(@old_UpdatedDate,'')    
        set @xml = @xml + '<ColumnInfo ColumnName="UpdatedDate" OldValue="'+ cast(IsNull(@old_UpdatedDate,'') as varchar(100)) + '" NewValue="' + cast(IsNull(@new_UpdatedDate,'') as varchar(100)) + '"/>'    

        -- UpdatedBy     
        If cast(IsNull(@new_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36)) != cast(IsNull(@old_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36))    
        set @xml = @xml + '<ColumnInfo ColumnName="UpdatedBy" OldValue="'+ cast(IsNull(@old_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36)) + '" NewValue="' + cast(IsNull(@new_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(36))+
        '"/>'    

        -- IsDeleted  
        If cast(IsNull(@new_IsDeleted,'') as varchar(10)) != cast(IsNull(@old_IsDeleted,'') as varchar(10))    
        set @xml = @xml + '<ColumnInfo ColumnName="IsDeleted" OldValue="'+ cast(IsNull(@old_IsDeleted,'') as varchar(10)) + '" NewValue="' + cast(IsNull(@new_IsDeleted,'') as varchar(10)) + '" />'    

        END    

        Set @xml = '<RowInfo TableName="te_Page" UpdatedBy="' + cast(IsNull(@new_UpdatedBy,'00000000-0000-0000-0000-000000000000') as varchar(50)) +  '" UpdatedDate="' + Convert(Varchar(20),GetDate()) + '">' + @xml + '</RowInfo>'    
        Select @ishistoryexists = RowHistory From DELETED     

        --print @ishistoryexists  


        If @ishistoryexists is null    
        Begin     
        Set @xml = '<History>' + @xml + '</History>'      
        Update te_Page    
        Set    
        RowHistory = @xml    
        Where     
        Id = @FormLineAttributeValueId    

        End    

        Else    
        Begin     
        set @xml = REPLACE(@currentxml, '<History>', '<History>' + @xml)  
        Update te_Page  
        Set  
        RowHistory = @xml  
        Where   
        Id = @FormLineAttributeValueId     
        End  


        FETCH NEXT FROM curFormId INTO @fmId  
        END   


        CLOSE curFormId  
        DEALLOCATE curFormId  

الآن كلما قمت بإجراء أي تحديث سيتم تخزين بياناتك فيه com.rowhistory عمود

إحدى الطرق التي رأيت فيها التعامل مع هذا (على الرغم من أنني لا أوصي به، بصراحة) هي التعامل معه عبر الإجراءات المخزنة، وتمرير معرف المستخدم/اسم المستخدم/أيًا كان كمعلمة.ستستدعي الإجراءات المخزنة إجراء التسجيل، الذي يكتب التفاصيل ذات الصلة في جدول سجل مركزي.

هنا حيث أصبح الأمر أحمق بعض الشيء، على الرغم من ...

بالنسبة للإدراجات/التحديثات، تم تخزين الصف (الصفوف) ذات الصلة في الجدول كبيانات XML بمجرد اكتمال INSERT/UPDATE بنجاح.بالنسبة لعمليات الحذف، تم تخزين الصف قبل تشغيل الحذف (رغم أنه من الناحية الواقعية، كان من الممكن أن يحصلوا عليه من مخرجات عبارة الحذف - على الأقل مع SQL Server 2005).

إذا كنت أتذكر بشكل صحيح، كان الجدول يحتوي على عمودين فقط:معرف المستخدم وتاريخ ووقت التسجيل ونوع المعاملة (I/U/D) وبيانات XML التي تحتوي على الصفوف ذات الصلة واسم الجدول وقيمة المفتاح الأساسي (تُستخدم بشكل أساسي للبحث السريع عن السجلات التي يريدونها).

طرق عديدة لسلخ جلد القطة...

نصيحتي هي أن تبقي بسيطة.قم بتوسيعه لاحقًا إذا/عندما تحتاج إلى ذلك.

إذا كانت لديك القدرة على القيام بذلك، فقم بتأمين المستخدمين حتى يتمكنوا فقط من تنفيذ بيانات قابلة للتنفيذ على الجداول من خلال الإجراءات المخزنة ثم التعامل مع التسجيل (كيفما تريد) من هناك.

لقد قمنا ببناء نظامنا الخاص ونحتاج فقط إلى تمرير المستخدم والكمبيوتر في كل إجراء مخزن للإضافة/التحديث.إذن فالأمر يتعلق فقط بالحصول على السجل الأصلي وملء المتغيرات ومقارنتها بالمتغيرات التي تم تمريرها وتسجيل البيانات في جدولنا.بالنسبة لعمليات الحذف، لدينا فقط نسخة من الجداول الأصلية + حقل الطابع الزمني، لذلك لا يتم حذف السجل أبدًا ويمكن استعادته في أي وقت نحتاج إليه (من الواضح عمليات التحقق الروتينية من علاقات FK وما شابه).

إضافة/تحديث جدول السجل يشبه DateTime ، table_name ، column_name ، record_id ، old_value ، new_value ، user_id ، الكمبيوتر

لا نقوم أبدًا بإدراج قيم خالية، لذلك نقوم بتحويلها إلى سلاسل فارغة، ويتم تمييز الإدخالات الجديدة بـ "{إدخال جديد}" في عمود القيمة القديمة.يتكون Record_id من العديد من الأعمدة الرئيسية لتعريف هذا السجل الفردي بشكل فريد ( field1 + '.' + field2 + ...)

أولاً، في جميع جداولك، يجب أن تتم إضافة هذه الأعمدة على الأقل إلى أعمدة البيانات DateCreated وUserCreated وDateModified وUserModified.ربما قد ترغب في إضافة عمود "الحالة" أو "الإجراء الأخير" حتى لا تقوم فعليًا بحذف صف ما، فقط قمت بتعيينه على حالة محذوفة/مدرجة/محدثة.بعد ذلك يمكنك إنشاء "جدول التاريخ" وهو نسخة طبق الأصل من الجدول الأول.بعد ذلك، في أي تحديثات أو عمليات حذف، اطلب من المشغل نسخ إدخالات الجدول المحذوفة في جدول المحفوظات مع تغيير حقول DateModified وUserModified وStatus في نفس الوقت.

لقد قمت بإعداد في SQL Server حيث نستخدم طرق العرض للوصول إلى بياناتنا، والتي من شأنها التعامل مع عمليات الإدراج والتحديثات والحذف بدلاً من المشغلات.

على سبيل المثال:ان بدلاً من الحذف سيؤدي المشغل الموجود في طريقة العرض إلى وضع علامة على السجلات الموجودة في الجدول الأساسي كمحذوفة، وتمت تصفية طريقة العرض حتى لا تظهر السجلات المحذوفة.

في جميع المشغلات، قمنا بتحديث تاريخ التعديل واسم المستخدم.المشكلة هي أن ذلك يسجل اسم مستخدم قاعدة البيانات، وهو ليس نفس اسم مستخدم التطبيق النهائي.

يجب أن يكون العرض مرتبطًا بالمخطط حتى يعمل هذا.

حول تسجيل المستخدمين الذين يغيرون قاعدة البيانات:يمكنك إنشاء أكبر عدد ممكن من مستخدمي SQL كما تحتاج إلى DB الخاص بك ، وإذا كنت تستخدم الجلسات والوصول المقيد/المسجل إلى البرنامج/البرنامج النصي ، يمكنك استخدام هذه المعلومات لبدء إعدادات اتصال DB مختلفة (أياسم المستخدم) ، قبل أي عملية مع DB.

على الأقل ينبغي أن يكون هذا ممكنًا بالنسبة للنصوص البرمجية المتوافقة مع لغة PHP، ولكن قد أكون مخطئًا بالنسبة لـ asp.net.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top