C# 在实体框架中的另一个DBContext中打开实体

C# 在实体框架中的另一个DBContext中打开实体,c#,asp.net-mvc,entity-framework,C#,Asp.net Mvc,Entity Framework,我从一个DBContext加载了一个实体,并对其进行了一些更改。如果我创建了另一个DBContext,我将如何从数据库中加载相同的实体?这需要在不同实体之间通用,因此我不能只查找ID相同的位置-某些实体可能具有不同的键属性 问题背后的原因是,我想使用加载到第二个上下文中的实体来验证第一个上下文中的一些更改属性,将以前的值与新值进行比较。因此,在验证第一个实体期间,第二个上下文是纯只读的 编辑 我尽量保持简单,我认为需要更多的细节 假设我有这个实体: public partial class S

我从一个DBContext加载了一个实体,并对其进行了一些更改。如果我创建了另一个DBContext,我将如何从数据库中加载相同的实体?这需要在不同实体之间通用,因此我不能只查找ID相同的位置-某些实体可能具有不同的键属性

问题背后的原因是,我想使用加载到第二个上下文中的实体来验证第一个上下文中的一些更改属性,将以前的值与新值进行比较。因此,在验证第一个实体期间,第二个上下文是纯只读的


编辑

我尽量保持简单,我认为需要更多的细节

假设我有这个实体:

public partial class SomeEntity : IValidatableObject
{
    public int Id { get; set; }

    public int StatusId { get; set; }

    //... Other properties

    public virtual ICollection<SomeOtherEntity> relatedEntity { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext){
        // validation code
    }
}
  • 重写
    MyDBContext
    上的
    ValidateEntity
    方法,以便将具有原始值的对象传递给实体上的验证方法

    public class MyDBContext : DbContext
    {
        protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
        {
            if (entityEntry.Entity is IMyValidationInterface)
            {
                var _validationContext = new MyDbContext();
    
                /// TODO: some code here to load a duplicated version of 
                ///       the entity from the database
    
                var originalEntity; // unchanged entity is here
    
                // unmodified entity is passed as an item to the entities
                // Validate method 
                items.Add("OriginalEntity", originalEntity);
             }
    
             return base.ValidateEntity(entityEntry, items);
         }
    }
    
    public partial class SomeEntity : IValidatableObject, IMyValidationInterface
    {
        // .....
    
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext){
            // validation code
            if (validationContext.Items.ContainsKey("OriginalEntity")){
                  var originalEntity = (SomeEntity)validationContext.Items["OriginalEntity"];
    
                  // do validation here and yield return any validation errors
            }
        }
    }
    
    公共类MyDBContext:DbContext
    {
    受保护的重写DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry,IDictionary项)
    {
    if(entityEntry.Entity为IMyValidationInterface)
    {
    var_validationContext=new MyDbContext();
    ///TODO:此处的一些代码用于加载的复制版本
    ///数据库中的实体
    var originalEntity;//此处有未更改的实体
    //未修改的实体作为项传递给实体
    //验证方法
    添加(“原始性”,原始性);
    }
    返回基数ValidateEntity(entityEntry,items);
    }
    }
    公共部分类SomeEntity:IValidatableObject,IMyValidationInterface
    {
    // .....
    公共IEnumerable验证(ValidationContext ValidationContext){
    //验证码
    if(validationContext.Items.ContainsKey(“OriginalEntity”)){
    var originalEntity=(SomeEntity)validationContext.Items[“originalEntity”];
    //在此处执行验证并返回任何验证错误
    }
    }
    }
    
  • 我被困在上面代码片段的待办事项部分


    我走错了吗?

    一种快速而肮脏的方法是,在修改原始状态之前,先将其存储到未映射到数据库的属性或字段中,理想情况下是从数据库加载原始状态

    interface IMaterializable
    {
        void OnMaterialized();
    }
    
    class SomeEntity : IMaterializable, IValidatableObject
    {
        public int Id { get; set; }
    
        public int StatusId { get; set; }
    
        //... Other properties
    
        public virtual ICollection<SomeOtherEntity> relatedEntity { get; set; }
    
        int OriginalStatusId;
    
        public void OnMaterialized()
        {
            OriginalStatusId = StatusId;
        }
    
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            // compare current status to original + related
        }
    }
    

    我最终对datacontext执行了以下操作:

    public class MyDBContext : DbContext
    {
        public virtual T GetEntityByPrimaryKey<T>(T entity) where T : class
        {
            var entityType = entity.GetType();
            var objectSet = ((IObjectContextAdapter)this).ObjectContext.CreateObjectSet<T>();
            var keyNames = objectSet.EntitySet.ElementType.KeyMembers.Select(edmMember => edmMember.Name);
            var keyValues = keyNames.Select(name => entityType.GetProperty(name).GetValue(entity, null)).ToArray();
    
            return this.Set<T>().Find(keyValues);
        }
    
        protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
        {
            if (entityEntry.Entity is IMyValidationInterface)
            {
                var validationContext = new MyDBContext();
    
                var modifiedEntity = entityEntry.Entity;
    
                var originalEntity = validationContext.GetEntityByPrimaryKey(a);
    
                items.Add("OriginalEntity", originalEntity);
            }
    
            return base.ValidateEntity(entityEntry, items);
        }
    }
    
    公共类MyDBContext:DbContext
    {
    公共虚拟T GetEntityByPrimaryKey(T实体),其中T:class
    {
    var entityType=entity.GetType();
    var objectSet=((IObjectContextAdapter)this.ObjectContext.CreateObjectSet();
    var keyNames=objectSet.EntitySet.ElementType.KeyMembers.Select(edmMember=>edmMember.Name);
    var keyValues=keyNames.Select(name=>entityType.GetProperty(name).GetValue(entity,null)).ToArray();
    返回此.Set().Find(keyValues);
    }
    受保护的重写DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry,IDictionary项)
    {
    if(entityEntry.Entity为IMyValidationInterface)
    {
    var validationContext=new MyDBContext();
    var modifiedEntity=entityEntry.Entity;
    var originalEntity=validationContext.GetEntityByPrimaryKey(a);
    添加(“原始性”,原始性);
    }
    返回基数ValidateEntity(entityEntry,items);
    }
    }
    

    GetEntityByPrimaryKey
    在此处找到

    是否保存从第一个DBContext加载的修改实体的更改?也许您可以使用原始值,而不必有多个上下文?我认为您只需要知道对实体进行了哪些更改以进行验证。如果有帮助,请检查此链接,[链接]:您是否考虑过直接查询EF模型以从实体获取实际的关键信息?这是我的计划B。确实,我希望在保存之前确保数据库中有最新版本。如果其他人在创建模型后但在保存模型之前对其进行更改,则数据库中的
    OriginalStatusId
    可能会有所不同。在验证过程中再次加载将降低此风险。
    void OnObjectMaterialized( object sender, ObjectMaterializedEventArgs e )
    {
        var entity = e.Entity as IMaterializable;
    
        if ( entity != null )
        {
            entity.OnMaterialized();
        }
    }
    
    public class MyDBContext : DbContext
    {
        public virtual T GetEntityByPrimaryKey<T>(T entity) where T : class
        {
            var entityType = entity.GetType();
            var objectSet = ((IObjectContextAdapter)this).ObjectContext.CreateObjectSet<T>();
            var keyNames = objectSet.EntitySet.ElementType.KeyMembers.Select(edmMember => edmMember.Name);
            var keyValues = keyNames.Select(name => entityType.GetProperty(name).GetValue(entity, null)).ToArray();
    
            return this.Set<T>().Find(keyValues);
        }
    
        protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
        {
            if (entityEntry.Entity is IMyValidationInterface)
            {
                var validationContext = new MyDBContext();
    
                var modifiedEntity = entityEntry.Entity;
    
                var originalEntity = validationContext.GetEntityByPrimaryKey(a);
    
                items.Add("OriginalEntity", originalEntity);
            }
    
            return base.ValidateEntity(entityEntry, items);
        }
    }