通用存储库EF 5 - 更新实体及其复杂/标量/导航属性

时间:2013-07-25 11:03:58

标签: entity-framework asp.net-mvc-4 repository entity asp.net-web-api

我正在尝试找到一个简单的解决方案来更新实体+我的解决方案中包含的属性。我为我的DBContext(数据库)创建了一个通用存储库。它确实更新了父实体,但没有处理子属性的更改。有没有办法处理或跟踪这些变化?

更新子级别的示例代码:(查看注释 - 示例代码)


    [HttpPut]
    public HttpResponseMessage PutBrand(Brand brand)
    {
        if (!ModelState.IsValid)
        {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        }

        try
        {
            // example code
            brand.BrandSizes.FirstOrDefault().Name = "I'm a Test";


            // add values
            brand.State = State.Changed;
            brand.DateChanged = DateTime.Now;

            // update
            brand = _brandService.UpdateBrand(brand);
            // save
            _brandService.SaveBrandChanges();
            // signalR
            Hub.Clients.All.UpdateBrand(brand);

            return Request.CreateResponse<Brand>(HttpStatusCode.OK, brand);
        }
        catch (Exception ex)
        {
            return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
        }
    }

上下文


public class ERPContext : DbContext
{
    #region Catalog

    public DbSet<Brand> Brands { get; set; }

    public DbSet<BrandSize> BrandSizes { get; set; }

    public DbSet<BrandSizeOption> BrandSizeOptions { get; set; }

    public DbSet<BrandTierPrice> BrandTierPrices { get; set; }

    #endregion Catalog


    public ERPContext()
        : base("db-erp")
    {
        Configuration.LazyLoadingEnabled = false;
        Configuration.ProxyCreationEnabled = false;
    }



    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();


    }
}

通用存储库:


public class ERPRepository<T> : IRepository<T> where T : class
{
    #region Fields

    private DbSet<T> _dbSet;
    private DbContext _dataContext;

    #endregion Fields

    #region Ctor

    public ERPRepository(DbContext dataContext)
    {
        if (dataContext == null)
        {
            throw new ArgumentNullException("dataContext", "dataContext cannot be null");
        }

        _dataContext = dataContext;
        _dbSet = _dataContext.Set<T>();
    }

    #endregion Ctor

    #region Methods

    public T Add(T item)
    {
        return _dbSet.Add(item);
    }

    public T Delete(T item)
    {
        return _dbSet.Remove(item);
    }

    public T Update(T item)
    {
        var updated = _dbSet.Attach(item);
        _dataContext.Entry(item).State = EntityState.Modified;
        return updated;
    }

    public IQueryable<T> Query(params Expression<Func<T, object>>[] includes)
    {
        var query = _dbSet;

        if (includes != null)
        {
            includes.ToList().ForEach(x => query.Include(x).Load());
        }

        return query;
    }

    public void SaveChanges()
    {
        _dataContext.SaveChanges();
    }

    #endregion Methods
}

型号:


public class Brand
{
    #region Ctr

    public Brand()
    {
        BrandSizes = new List<BrandSize>();
        BrandTierPrices = new List<BrandTierPrice>();
    }

    #endregion Ctr

    #region Properties

    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public int? LogoId { get; set; }

    public int DisplayOrder { get; set; }

    public bool Deleted { get; set; }

    public bool Locked { get; set; }

    public State State { get; set; }

    public DateTime DateChanged { get; set; }

    public DateTime DateCreated { get; set; }

    #endregion Properties

    #region Mapping

    public virtual Picture Logo { get; set; }

    public virtual List<BrandSize> BrandSizes { get; set; }

    public virtual List<BrandTierPrice> BrandTierPrices { get; set; }

    #endregion Mapping
}

BrandService:


public partial class BrandService : IBrandService
{
    #region Fields

    private readonly IRepository<Brand> _brandRepository;
    private readonly IRepository<BrandSize> _brandSizeRepository;
    private readonly IRepository<BrandSizeOption> _brandSizeOptionRepository;

    #endregion Fields

    #region Ctor

    public BrandService(IRepository<Brand> brandRepository, IRepository<BrandSize> brandSizeRepository, IRepository<BrandSizeOption> brandSizeOptionRepository)
    {
        _brandRepository = brandRepository;
        _brandSizeRepository = brandSizeRepository;
        _brandSizeOptionRepository = brandSizeOptionRepository;
    }

    #endregion Ctor

    #region Methods


    public virtual IEnumerable<Brand> GetAllBrands()
    {
        return _brandRepository.Query(x => x.BrandSizes);

        //return _brandRepository.Query();
    }

    public virtual Brand GetBrandById(int id)
    {
        return _brandRepository.Query().Where(x => x.Id == id).FirstOrDefault();
    }

    public virtual Brand InsertBrand(Brand brand)
    {
        return _brandRepository.Add(brand);
    }

    public virtual Brand UpdateBrand(Brand brand)
    {
        return _brandRepository.Update(brand);
    }

    public virtual Brand DeleteBrand(Brand brand)
    {
        return _brandRepository.Delete(brand);
    }

    public virtual void SaveBrandChanges()
    {
        _brandRepository.SaveChanges();
    }



    #endregion Methods
}

1 个答案:

答案 0 :(得分:0)

创建IObjectWithState接口和State enum以手动跟踪更改:

public interface IObjectWithState
{
    State State { get; set; }
}

public enum State
{
    Added,
    Unchanged,
    Modified,
    Deleted
}

并在每个映射实体中实现接口

 public class Brand:IObjectWithState
{ ....
[NotMapped]
    public State State { get; set; }}

并添加这两个辅助方法来转换状态并在整个图中应用更改:

public static EntityState ConvertState(State state)
    {
        switch (state)
        {
            case State.Added :
                return EntityState.Added;
            case State.Deleted:
                return EntityState.Deleted;
            case State.Modified:
                return EntityState.Modified;
            case State.Unchanged:
                return EntityState.Unchanged;
            default:
                return EntityState.Unchanged;
        }
    }

    public static void ApplyStateChanges(this DbContext context)
    {
        foreach (var entry in context.ChangeTracker.Entries<IObjectWithState>())
        {
            IObjectWithState stateInfo = entry.Entity;
            entry.State = StateHelpers.ConvertState(stateInfo.State);
        }
    }

当更新或插入任何对象时,编辑它的状态,如object.State = State.Modified; 然后将您的插入或更新方法修改为:

 public void InsertOrUpdate(T entity, bool IsGraph)
    {
        if (((IObjectWithState)entity).State == State.Added)
        {
            dataContext.Entry(entity).State = System.Data.Entity.EntityState.Added;
        }
        else
        {
            dbset.Add(entity);
            dataContext.Entry(entity).State = System.Data.Entity.EntityState.Modified;
        }
        //This method change the state of every changed object
        if (IsGraph)
            ApplyStateChanges(dataContext);
        dataContext.Commit();
    }