Closed DotNetFire closed 5 years ago
Could you post your EntityBase
class definition?
Below is the complete EntityBase class:
using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.Infrastructure;
using EntityFramework.Triggers;
namespace DotNetFire.Data.Entity {
public abstract class EntityBase {
static EntityBase() {
Triggers<EntityBase>.Inserting += entity => {
entity.Entity.Created = entity.Entity.Updated = DateTime.UtcNow;
entity.Entity.Version = 1;
};
Triggers<EntityBase>.Updating += entity => {
//if (entity.Original.Version != entity.Entity.Version) {
if (entity.Context.Entry(entity.Entity).OriginalValues.ToObject() is EntityBase org && org.Version != entity.Entity.Version) {
entity.Cancel = true;
// ReSharper disable once PossibleNullReferenceException
var entityName = entity.Entity.GetType().BaseType != null
&& entity.Entity.GetType().Name.StartsWith(entity.Entity.GetType().BaseType.Name)
// ReSharper disable once PossibleNullReferenceException
? entity.Entity.GetType().BaseType.Name
: entity.Entity.GetType().Name;
throw new DbUpdateConcurrencyException(
$"Validation failed for entitiy {entityName} with id {entity.Entity.Id}. Version in Database in different from version in Entity.");
}
entity.Entity.Updated = DateTime.UtcNow;
entity.Entity.Version += 1;
};
}
[Key]
//TODO: Generate from Sequence with MandantId!!
public long Id { get; set; }
public int Version { get; set; } = 1;
public DateTime Created { get; set; } = DateTime.UtcNow;
public DateTime Updated { get; set; } = DateTime.UtcNow;
}
}
Thx Stefan
It appears that the original values cannot be retrieved using the proxy objects created by EF for lazy loading.
The solution appears to be mentioned here: https://github.com/NickStrupat/EntityFramework.Triggers/issues/24
Might want to leave this one open so you don't get the same question again, just mark it as solved or something...
Googling on the error only points towards this post, until you only search for "OriginalValuesWrapperAssembly", then you'll find the old closed ones aswell.
After further research, i found that your TypedOriginalValues project found here which is where the problem is.
The below is my fixed entity:
namespace ADDER.VAT.Data.Models
{
public abstract class EntityBase
{
static EntityBase()
{
Triggers<EntityBase>.Inserting += OnInserting;
Triggers<EntityBase>.Updating += OnUpdating;
}
private static void OnUpdating(IUpdatingEntry<EntityBase, DbContext> e)
{
// These make sure that the value of CreatedAt and CreatedById stay the same
e.Entity.CreatedAt = (DateTime)e.Context.Entry(e.Entity).Property(nameof(CreatedAt)).OriginalValue;
e.Entity.CreatedById = (string)e.Context.Entry(e.Entity).Property(nameof(CreatedById)).OriginalValue;
// These update the UpdatedAt and UpdatedById to whoever is responsible for the current update
e.Entity.UpdatedAt = DateTime.Now;
e.Entity.UpdatedById = Thread.CurrentPrincipal.Identity.GetUserId();
}
private static void OnInserting(IInsertingEntry<EntityBase, DbContext> e)
{
e.Entity.CreatedAt = e.Entity.UpdatedAt = DateTime.Now;
e.Entity.CreatedById = e.Entity.UpdatedById = Thread.CurrentPrincipal.Identity.GetUserId();
}
[Key]
[Column("ID")]
public virtual int Id { get; set; }
public virtual DateTime CreatedAt { get; set; }
[Required]
public virtual string CreatedById { get; set; }
public virtual DateTime UpdatedAt { get; set; }
[Required]
public virtual string UpdatedById { get; set; }
// Navigation properties
[ForeignKey(nameof(CreatedById))]
public virtual ApplicationUser CreatedBy { get; set; }
[ForeignKey(nameof(UpdatedById))]
public virtual ApplicationUser UpdatedBy { get; set; }
}
}
Originally i had these 2 for lines 22/23:
e.Entity.CreatedAt = e.Original.CreatedAt;
e.Entity.CreatedById = e.Original.CreatedById;
The following code does not work, when Entity is a proxy:
Exception is:
I could solve the problem by changing the line
to
It may be a problem of EntityFramework.TypedOriginalValues...