personally I think you two are depending on a business layer to do what you should be handling by database design.
What I recommended isnt hard to implement, and its a lot easier than trying to wire up classes of objects to handle the implementation.
CREATE TABLE [dbo].[Doctors](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[DisplayName] [varchar](210) COLLATE Latin1_General_CI_AI NULL,
[FirstName] [varchar](50) COLLATE Latin1_General_CI_AI NULL,
[LastName] [varchar](50) COLLATE Latin1_General_CI_AI NULL,
[MiddleName] [varchar](50) COLLATE Latin1_General_CI_AI NULL,
[Credentials] [varchar](50) COLLATE Latin1_General_CI_AI NULL,
[GroupID] [bigint] NOT NULL CONSTRAINT [DF_Doctors_GroupID] DEFAULT ((1)),
[Active] [bit] NOT NULL CONSTRAINT [DF_Doctors_Active] DEFAULT ((1)),
[AddDate] [datetime] NULL,
[AddUserID] [varchar](50) COLLATE Latin1_General_CI_AI NULL,
[ChangeDate] [datetime] NULL,
[ChangeUserID] [varchar](50) COLLATE Latin1_General_CI_AI NULL,
CONSTRAINT [PK_Doctors] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
There you have generally what you need for auditing. In you save routine you pass in what you need from your currentprincipal and the Now() function..and you have row level audits.
then you create an onUpdate trigger that copies the original values to a dump table before they are overwritten.
Simple as boiling water.