EntityFramework-Plus icon indicating copy to clipboard operation
EntityFramework-Plus copied to clipboard

Custom Class and Auto PreSave

Open dineplan opened this issue 9 years ago • 9 comments

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 ?

dineplan avatar Oct 03 '16 08:10 dineplan

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.

zzzprojects avatar Oct 03 '16 14:10 zzzprojects

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>());

dineplan avatar Oct 05 '16 05:10 dineplan

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.

zzzprojects avatar Oct 05 '16 14:10 zzzprojects

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

KarishImrith avatar Oct 19 '16 16:10 KarishImrith

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

zzzprojects avatar Oct 19 '16 18:10 zzzprojects

Can you give me a sample class of a working CustomAuditEntry and CustomerAuditEntryProperty? I am having the same problem

primerocarlos avatar Oct 03 '17 11:10 primerocarlos

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

JonathanMagnan avatar Oct 04 '17 02:10 JonathanMagnan

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 .

primerocarlos avatar Oct 04 '17 06:10 primerocarlos

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.

dongjason avatar Aug 05 '20 19:08 dongjason