EF6 - 在 SaveChanges() 上有条件地更新实体 属性

EF6 - Conditionally updating an Entity property on SaveChanges()

我正在使用 EF6 代码优先(来自现有数据库)来执行 CRUD 操作。我打算在这里写一些模拟代码来解释,因为由于一些版权问题我无法粘贴真正的代码。 这是我的实体:

    public partial class Person : EntityBase
{
    public long Id { get; set; } // ID (Primary key)
    public string LastName { get; set; } // LastName (length: 50)
    public string FirstName { get; set; } // FirstName (length: 50)
    public string SocialSecurity { get; set; } // SocialSecurity (length: 50)
    public long CreatedById { get; set; } // CreatedByID
    public System.DateTime CreatedDate { get; set; } // CreatedDate
    public long UpdatedById { get; set; } // UpdatedByID
    public System.DateTime UpdatedDate { get; set; } // UpdatedDate
    public byte[] TimeStamped { get; set; } // TimeStamped (length: 8)
}

我有一个通用存储库来执行 CRUD 操作。

    public class Repository<T> : IRepositoryAsync<T> where T : class, IObjectState
{
    private readonly IDataContextAsync context;
    private readonly DbSet<T> dbSet;
    //private read-only IUnitOfWorkAsync uow;

    public Repository( IDataContextAsync _context )
    {
        context = _context;
        dbSet = ( (DbContext)context ).Set<T>();
    }

    public virtual IDataContextAsync Context { get { return context; } }
    public IDbSet<T> DbSet { get { return dbSet; } }
    public T FindOne( Expression<Func<T, bool>> predicate )
    {
        return dbSet.SingleOrDefault( predicate );
    }
    public IQueryable<T> FindBy( Expression<Func<T, bool>> predicate )
    {
        return dbSet.Where( predicate );
    }
    public void Add( T entity )
    {
        //entity.ObjectStateEnum = ObjectStateEnum.Added;
        dbSet.Add( entity );
    }
    public void Delete( dynamic id )
    {
        var entity = dbSet.Find(id);
        Delete( entity );
    }
    public void Update( T entity )
    {
        //entity.ObjectStateEnum = ObjectStateEnum.Modified;
        dbSet.Add( entity );
    }
}

这是我的 UnitOfWork 实现。同样,代码片段只是片段。代码不完整。

    public class UnitOfWork : IUnitOfWorkAsync
{
    private IDataContextAsync context;
    private IOperationStatus opStatus;
    private Dictionary<string, dynamic> repositories;
    private ObjectContext objectContext;
    private DbTransaction transaction;
    private bool disposed;

    public IDataContextAsync DataContext { get { return context; } }

    //public UnitOfWork()
    //{
    //  context = new RedStoneDbContext(); //???? _context;
    //  opStatus = new OperationStatus(); //???? _opStatus;
    //  repositories = new Dictionary<string, dynamic>();
    //}
    public UnitOfWork( IDataContextAsync _context, IOperationStatus _opStatus )
    {
        context = _context;
        opStatus = _opStatus;
        repositories = new Dictionary<string, dynamic>();
    }

    public IOperationStatus SaveChanges()
    {
        opStatus.Success = false;
        try
        {
            int numRec = context.SaveChanges();
            opStatus.Success = true;
            opStatus.RecordsAffected = numRec;
        }
        catch ( SystemException ex )
        {
            opStatus = opStatus.CreateFromException( ex );
        }
        return opStatus;
    }
    public void Dispose()
    {
        Dispose( true );
        GC.SuppressFinalize( this );
    }

    public virtual void Dispose( bool disposing )
    {
        if ( disposed )
            return;

        if ( disposing )
        {
            try
            {
                if ( objectContext != null && objectContext.Connection.State == ConnectionState.Open )
                    objectContext.Connection.Close();
            }
            catch ( ObjectDisposedException )
            {
                // do nothing
            }
            if ( context != null )
            {
                context.Dispose();
                context = null;
            }
        }
        disposed = true;
    }
    public IRepository<T> Repository<T>() where T : class, IObjectState
    {
        return RepositoryAsync<T>();
    }

    public async Task<IOperationStatus> SaveChangesAsync()
    {
        opStatus.Success = false;
        try
        {
            int numRec = await context.SaveChangesAsync();
            opStatus.Success = true;
            opStatus.Message = "Record successfully saved!";
            opStatus.RecordsAffected = numRec;
        }
        catch ( DbUpdateConcurrencyException ex )
        {
            opStatus = opStatus.CreateFromException( ex );
        }
        catch ( SystemException ex )
        {
            opStatus = opStatus.CreateFromException( ex );
        }
        return opStatus;
    }
}

所以,这是我的问题。调用 savechanges 时,我想查看实体是否包含列 "SocialSecurity",如果有,我会查看用户的角色和权限。如果一切正常,想让传入的 SSN 持久化在数据库中。如果没有,我只希望 SaveChanges 简单地忽略 SocialSecurity 属性 但像往常一样更新其他所有内容。我想不出一种简单有效的方法来做到这一点。非常感谢任何帮助。

巴布.

您在这里拥有所需操作的所有逻辑推理,只是您将逻辑本身放在哪里以及您需要做什么的问题。

您应该为客户端代码调用以检索数据的每种类型提供某种服务,无论是相关的还是过滤的等。不允许通过存储库直接调用数据库的 IQueryable - 我不能从您的代码中判断您是否正在实施它们。

如果您有这些服务,那么您可以直接检查任何具有 SocialSecurity 实体的权限。 或者,您可以创建一个定义 SocialSecurity 的接口,并使用它适当地标记所有实体。 无论哪种方式,您都可以在适用时执行角色检查。

如果角色检查失败,您将需要从存储中加载当前实体,并且:

将当前保存的实体上的 SocialSecurity 属性 替换为从存储中加载的实体。

更新新加载的实体中的所有相关属性(SocialSecurity 值除外)

现在您可以执行更新(实体)了。

没有捷径可以做到这一点,更新操作背后有逻辑,需要直接保存(如果授予权限),或者在确保使用当前(来自存储)SocialSecurity 值的同时保存,而不是任何改变一个。

但是,考虑一下,您可以颠倒它,如果用户在加载页面时没有权限,则根本不允许用户编辑 SocialSecurity 值。 向没有权限的用户显示数据或给人以正在编辑的印象通常是不好的做法。 这可能是处理问题的更好方法。