我正在尝试找到一个简单的解决方案来更新实体+我的解决方案中包含的属性。我为我的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
}
答案 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();
}