EF6 - 有条件地更新SaveChanges()上的Entity属性

时间:2017-01-11 17:07:28

标签: c# entity-framework-6 repository unit-of-work

我正在使用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时,我想看看实体是否包含一个列&#34; SocialSecurity&#34;如果有,我会查看用户的角色和权限。如果一切正常,想让传入的SSN持久存储在数据库中。如果没有,我只想让SaveChanges忽略SocialSecurity属性,但像往常一样更新其他所有内容。我无法找到一种简单有效的方法来做到这一点。任何帮助都非常感谢。

巴布。

1 个答案:

答案 0 :(得分:0)

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

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

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

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

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

或者

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

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

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

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