问题
I have setup EF+ Audit as follows:
public partial class FocusConnection : DbContext
{
    static FocusConnection()
    {
        AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) =>
           // ADD "Where(x => x.AuditEntryID == 0)" to allow multiple SaveChanges with same Audit
           (context as FocusConnection).AuditEntries.AddRange(audit.Entries);
    }
    public override int SaveChanges()
    {
        var audit = new Audit();
        audit.PreSaveChanges(this);
        var rowAffecteds = base.SaveChanges();
        audit.PostSaveChanges();
        if (audit.Configuration.AutoSavePreAction != null)
        {
            audit.Configuration.AutoSavePreAction(this, audit);
            base.SaveChanges();
        }
        return rowAffecteds;
    }
    public override Task<int> SaveChangesAsync()
    {
        return SaveChangesAsync(CancellationToken.None);
    }
    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken)
    {
        var audit = new Audit();
        audit.PreSaveChanges(this);
        var rowAffecteds = await base.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
        audit.PostSaveChanges();
        if (audit.Configuration.AutoSavePreAction != null)
        {
            audit.Configuration.AutoSavePreAction(this, audit);
            await base.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
        }
        return rowAffecteds;
    }
}
I used a partial class to stay out to the text-templated original context generated by EF6. I used the following SQL script to generate the two table as-is:
CREATE TABLE [dbo].[AuditEntries] (
    [AuditEntryID] [int] NOT NULL IDENTITY,
    [EntitySetName] [nvarchar](255),
    [EntityTypeName] [nvarchar](255),
    [State] [int] NOT NULL,
    [StateName] [nvarchar](255),
    [CreatedBy] [nvarchar](255),
    [CreatedDate] [datetime] NOT NULL,
    CONSTRAINT [PK_dbo.AuditEntries] PRIMARY KEY ([AuditEntryID])
)
GO
CREATE TABLE [dbo].[AuditEntryProperties] (
    [AuditEntryPropertyID] [int] NOT NULL IDENTITY,
    [AuditEntryID] [int] NOT NULL,
    [RelationName] [nvarchar](255),
    [PropertyName] [nvarchar](255),
    [OldValue] [nvarchar](max),
    [NewValue] [nvarchar](max),
    CONSTRAINT [PK_dbo.AuditEntryProperties] PRIMARY KEY ([AuditEntryPropertyID])
)
GO
CREATE INDEX [IX_AuditEntryID] ON [dbo].[AuditEntryProperties]([AuditEntryID])
GO
ALTER TABLE [dbo].[AuditEntryProperties] 
ADD CONSTRAINT [FK_dbo.AuditEntryProperties_dbo.AuditEntries_AuditEntryID] 
FOREIGN KEY ([AuditEntryID])
REFERENCES [dbo].[AuditEntries] ([AuditEntryID])
ON DELETE CASCADE
GO
I'm getting an error in the static constructor:
static FocusConnection()
{
    AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) =>
        // ADD "Where(x => x.AuditEntryID == 0)" to allow multiple SaveChanges with same Audit
        (context as FocusConnection).AuditEntries.AddRange(audit.Entries);
}
Error on AuditEntries.AddRange(audit.Entries):
CS1503  Argument 1: cannot convert from System.Collections.Generic.List<Z.EntityFramework.Plus.AuditEntry> to System.Collections.Generic.IEnumerable<DA.Systems.Focus.Data.EntityFramework.FocusOrm.AuditEntry>
Am I missing something?
回答1:
You use Database First.
The AuditEntry class from EF+ is not the same as the one generated by your context.
You need to Import value.
AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) =>
{
    // ADD "Where(x => x.AuditEntryID == 0)" to allow multiple SaveChanges with same Audit
    var customAuditEntries = audit.Entries.Select(x => Import(x));
    (context as Entities).AuditEntries.AddRange(customAuditEntries);
};
using (var ctx = new Entities())
{
    Audit audit = new Audit();
    audit.CreatedBy = "ZZZ Projects"; // Optional
    ctx.Entity_Basic.Add(new Entity_Basic() {ColumnInt = 2});
    ctx.SaveChanges(audit);
}
public AuditEntry Import(Z.EntityFramework.Plus.AuditEntry entry)
{
    var customAuditEntry = new AuditEntry
    {
        EntitySetName = entry.EntitySetName,
        EntityTypeName = entry.EntityTypeName,
        State = (int)entry.State,
        StateName = entry.StateName,
        CreatedBy = entry.CreatedBy,
        CreatedDate = entry.CreatedDate
    };
    customAuditEntry.AuditEntryProperties = entry.Properties.Select(x => Import(x)).ToList();
    return customAuditEntry;
}
public AuditEntryProperty Import(Z.EntityFramework.Plus.AuditEntryProperty property)
{
    var customAuditEntry = new AuditEntryProperty
    {
        RelationName = property.RelationName,
        PropertyName = property.PropertyName,
        OldValue = property.OldValueFormatted,
        NewValue = property.NewValueFormatted
    };
    return customAuditEntry;
}
    来源:https://stackoverflow.com/questions/50537800/database-first-approach-with-automatic-crud-logging