Custom Class and Auto PreSave
I was trying to Create a Custom Class to Inherit AuditEntry and added my own property
But i am unable to use the AUTO PRESAVE
How to acheive that ?
If you don't have customized the DbSet, you can use it as you do it without customization
public class EntityContext : DbContext
{
// ... context code ...
public DbSet<AuditEntry> AuditEntries { get; set; }
public DbSet<AuditEntryProperty> AuditEntryProperties { get; set; }
}
AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) =>
// ADD "Where(x => x.AuditEntryID == 0)" to allow multiple SaveChanges with same Audit
(context as EntityContext).AuditEntries.AddRange(audit.Entries);
However, if you also have a custom DbSet, you must cast the list to the DbSet element type.
public class EntityContext : DbContext
{
// ... context code ...
public DbSet<CustomAuditEntry> CustomAuditEntries { get; set; }
public DbSet<CustomAuditEntryProperty> CustomAuditEntryProperties { get; set; }
}
AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) =>
// ADD "Where(x => x.AuditEntryID == 0)" to allow multiple SaveChanges with same Audit
(context as EntityContext).CustomAuditEntries.AddRange(audit.Entries.Cast<CustomAuditEntry>());
var audit = new Audit();
audit.CreatedBy = "ZZZ Projects"; // Optional
ctx.SaveChanges(audit);
We added the example here
Let me know if you successfully make it work, or you have a different scenario.
I am getting the following exception as
{"Unable to cast object of type 'Z.EntityFramework.Plus.AuditEntry' to type 'DinePlan.DineConnect.Audit.TenantAuditEntry'."}
and my code is
AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) => (context as DineConnectDbContext).CustomAuditEntries.AddRange(audit.Entries.Cast<TenantAuditEntry>());
Do your class inherit from Audit Entry? If yes, did you use the AuditEntryFactory property?
You can learn more about Audit Customization here
If you want, you could also send us a project sample, and we will help you.
Hi there,
This package is amazing! Makes things so much easier. However a feature is missing: I want to store audit logs in different tables per entity type because I fear that having all the logs on one table is going to cause a performance issue. Example: CustomerAuditEntry, CustomerAuditEntryProperty (so customer logs will be stored on these tables) and ProductAuditEntry, ProductAuditEntryProperty (so product logs will be stored on these tables). Thus each type has its own log tables and preventing one huge table.
On trying to work around your package to get my goal, I ran into the problem that has been posted. Cannot cast from Base class to Sub class.
Your assistance is appreciated.
Regards
Hello @KarishImrith ,
Since this question may lead to more questions, I answered in a new issue to make it easier to make a follow-up.
Please see the answer in the Issue #63
Can you give me a sample class of a working CustomAuditEntry and CustomerAuditEntryProperty? I am having the same problem
Hello @primerocarlos ,
Here is an example
using System.Data.Entity;
using System.Windows.Forms;
namespace Z.EntityFramework.Plus.Lab
{
public partial class Form_Request_Audit_CustomAudit : Form
{
public Form_Request_Audit_CustomAudit()
{
InitializeComponent();
AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) =>
(context as EntityContext).AuditEntries.AddRange(audit.Entries);
AuditManager.DefaultConfiguration.AuditEntryFactory = args =>
new CustomAuditEntry {CustomProperty = 1};
AuditManager.DefaultConfiguration.AuditEntryPropertyFactory = args =>
new CustomAuditEntryProperty {CustomProperty = 2};
using (var ctx = new EntityContext())
{
var audits = new Audit();
audits.CreatedBy = "ZZZ Projects"; // Optional
ctx.EntitySimples.Add(new EntitySimple {ColumnInt = 2});
ctx.SaveChanges(audits);
}
}
public class EntityContext : DbContext
{
public EntityContext() : base("CodeFirstEntities")
{
}
// ... context code ...
public DbSet<AuditEntry> AuditEntries { get; set; }
public DbSet<AuditEntryProperty> AuditEntryProperties { get; set; }
public DbSet<EntitySimple> EntitySimples { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// MAP audit using TPH
modelBuilder.Entity<AuditEntry>().Map<CustomAuditEntry>(x => x.Requires("Discriminator").HasValue("CustomAuditEntry"));
modelBuilder.Entity<AuditEntryProperty>().Map<CustomAuditEntryProperty>(x => x.Requires("Discriminator").HasValue("CustomAuditEntryProperty"));
base.OnModelCreating(modelBuilder);
}
}
}
public class EntitySimple
{
public int ID { get; set; }
public int ColumnInt { get; set; }
}
public class CustomAuditEntry : AuditEntry
{
public int CustomProperty { get; set; }
}
public class CustomAuditEntryProperty : AuditEntryProperty
{
public int CustomProperty { get; set; }
}
}
Best Regards,
Jonathan
Hi Jonathan,
Thanks!
On Oct 4, 2017 6:13 AM, "Jonathan Magnan" [email protected] wrote:
Hello @primerocarlos https://github.com/primerocarlos ,
Here is an example
using System.Data.Entity;using System.Windows.Forms; namespace Z.EntityFramework.Plus.Lab { public partial class Form_Request_Audit_CustomAudit : Form { public Form_Request_Audit_CustomAudit() { InitializeComponent();
AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) => (context as EntityContext).AuditEntries.AddRange(audit.Entries); AuditManager.DefaultConfiguration.AuditEntryFactory = args => new CustomAuditEntry {CustomProperty = 1}; AuditManager.DefaultConfiguration.AuditEntryPropertyFactory = args => new CustomAuditEntryProperty {CustomProperty = 2}; using (var ctx = new EntityContext()) { var audits = new Audit(); audits.CreatedBy = "ZZZ Projects"; // Optional ctx.EntitySimples.Add(new EntitySimple {ColumnInt = 2}); ctx.SaveChanges(audits); } } public class EntityContext : DbContext { public EntityContext() : base("CodeFirstEntities") { } // ... context code ... public DbSet<AuditEntry> AuditEntries { get; set; } public DbSet<AuditEntryProperty> AuditEntryProperties { get; set; } public DbSet<EntitySimple> EntitySimples { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // MAP audit using TPH modelBuilder.Entity<AuditEntry>().Map<CustomAuditEntry>(x => x.Requires("Discriminator").HasValue("CustomAuditEntry")); modelBuilder.Entity<AuditEntryProperty>().Map<CustomAuditEntryProperty>(x => x.Requires("Discriminator").HasValue("CustomAuditEntryProperty")); base.OnModelCreating(modelBuilder); } } } public class EntitySimple { public int ID { get; set; } public int ColumnInt { get; set; } } public class CustomAuditEntry : AuditEntry { public int CustomProperty { get; set; } } public class CustomAuditEntryProperty : AuditEntryProperty { public int CustomProperty { get; set; } }}
Best Regards,
Jonathan
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/zzzprojects/EntityFramework-Plus/issues/56#issuecomment-334031518, or mute the thread https://github.com/notifications/unsubscribe-auth/ATgdRY7vXc0WpLptfL7rowUAw-1wY8TBks5sounXgaJpZM4KMWjY .
In this example code, the "CustomProperty" seems assigned the same value. Is there a way to assign the value based on values of the entity being auditted?
It would be nice to configure a function so that the CustomProperty value is assigned with output of a function with the auditted entity as a parameter.