I am using entity framework 6 and i have a base entity called EntityBase, very simple as so
public abstract class EntityBase : IEntityBase
{
public virtual long Id { get; set; }
}
Each of my entities inherit from this. Now some entities need audit information, so i have first created an interface called IAudit
public interface IAudit
{
Audit Audit { get; set; }
}
And the Audit object like so
public class Audit
{
public bool IsDeleted { get; set; }
public DateTime? DeletedDate { get; set; }
public long? DeletedByUserId { get; set; }
public DateTime CreatedDate { get; set; }
public long CreatedByUserId { get; set; }
public DateTime UpdatedDate { get; set; }
public long UpdatedByUserId { get; set; }
public byte[] RowVersion { get; set; }
}
And if an entity needs audit information, i apply this interface. Here is an example
public class Attachment : EntityBase, IAudit
{
#region IAudit
public Audit Audit { get; set; }
#endregion
public string Name { get; set; }
}
I am using code first, so now in my DbContext, i have this in my OnModelCreating method
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new AttachmentConfig());
}
Here is my AttachmentConfig file, which inherits from EntityBaseConfig, both included below
public abstract class EntityBaseConfig<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : EntityBase
{
public EntityBaseConfig()
{
this.HasKey(e => e.Id);
}
}
class AttachmentConfig : EntityBaseConfig<Attachment>
{
public AttachmentConfig()
: base()
{
this.Property(e => e.Name)
.HasMaxLength(255)
.IsRequired();
}
}
Now when my table is created, the Attachment table has the columns i would expect, but Audit_RowVersion is varbinary(max) instead of timestamp.
I have tried to put this line in each config file but get this error.
this.Property(e => e.Audit.RowVersion).IsRowVersion();
Schema specified is not valid. Errors: (36,14) : error 2039: The conceptual side property 'RowVersion' has already been mapped to a storage property with type 'rowversion'. If the conceptual side property is mapped to multiple properties in the storage model, make sure that all the properties in the storage model have the same type.
But i do not want to write this line in each file anyway. How can i get the Audit.RowVersion column to generate as a timestamp, and ideally write it once, so that all objects that implement IAudit also get the configured fields?
EDIT:
I have now added a config file for the Audit object, which looks like this
public class AuditConfig : EntityTypeConfiguration<Audit>
{
public AuditConfig() : base()
{
this.Property(e => e.RowVersion)
.IsRowVersion();
}
}
And i call this in the OnModelCreating method, like so, before the other Configuration calls
modelBuilder.Configurations.Add(new AuditConfig());
Now when i run my project, i get the following error
A table can only have one timestamp column. Because table 'Attachment' already has one, the column 'Audit_RowVersion' cannot be added.
If i look at the database and Attachment table created so far, it has the fields in the Audit object, but they do not have the Audit_ prefix? Maybe this is a clue to someone?
You can use DataAnnotations.
In your model class
public class Audit
{
public bool IsDeleted { get; set; }
public DateTime? DeletedDate { get; set; }
public long? DeletedByUserId { get; set; }
public DateTime CreatedDate { get; set; }
public long CreatedByUserId { get; set; }
public DateTime UpdatedDate { get; set; }
public long UpdatedByUserId { get; set; }
[TimeStamp]
public byte[] RowVersion { get; set; }
}
You can add [TimeStamp] Attribute for your variable.