У меня есть Users - Rules
таблицы с many-to-many
отношениями. Я хочу удалить некоторые правила определенного пользователя и обновить одно поле этого пользователя в том же шаге / транзакции базы данных, поэтому у меня есть следующий псевдокод в BL:
this.UnitOfWork.ExecuteTransaction(() =>
{
// delete rules
foreach (var rule in ruleList)
repoRules.DeleteRulesForUser(user, rule);
// update user field
repoUser.UpdateUserField(user);
}
В репозиториях EF:
public void DeleteRulesForUser(User user, Rule rule)
{
// check user
EFUser u = this.dbContext.EFUsers.Find(user.UID);
if (u == null)
throw new DBModuleException();
// check rule
EFRule r = this.dbContext.EFRules.Find(rule.UID);
if (r == null)
throw new DBModuleException();
// detach previous entities, so that we can attach with relation
this.dbContext.ObjectContext.Detach(u);
this.dbContext.ObjectContext.Detach(r);
// prepare entities
var efUser = new EFUser { US_UID = user.UID };
var efRule = new EFRule { RU_UID = rule.UID };
efRule.Users.Add(efUser);
// attach
this.dbContext.EFRules.Attach(efRule);
// delete relation
efRule.Users.Remove(efUser);
}
public void UpdateUserField(User user)
{
// get updating user
EFUser efUser = this.dbContext.EFUsers.FirstOrDefault(u => u.UID == user.UID);
if (efUser == null)
throw new DBModuleException("Not found!");
// perform update
efUser.US_Field = user.Field;
}
Моя реализация UnitOfWork (только с EF6 или выше):
public override void ExecuteTransaction(Action transAction)
{
// make sure to make IsolationLevel flexible later
using (var dbTransaction = this.dbContext.Database
.BeginTransaction(IsolationLevel.ReadCommitted))
{
try
{
transAction();
// save changes if not done yet
this.dbContext.SaveChanges();
// commit transaction
dbTransaction.Commit();
}
catch (System.Data.DataException ex)
{
// rollback
dbTransaction.Rollback();
// handling exception ceremony comes here
}
}
Моя проблема в том, что DeleteRulesForUser
прикрепляет этого пользователя только с UID (как указано в методе), но затем, позже в UpdateUserField
EF предоставляет этому пользователю только UID, вместо того, чтобы получать от пользователя полные данные, потому что FirstOrDefault
вызывает базу данных. Я предполагаю, что так работает кеш EF (?). В любом случае операция обновления не выполняется, и я хочу узнать, как решить эту проблему.
Я вижу необходимость иногда загружать объект только с UID, но иногда и с полными данными.
Я думал отделить объекты в конце метода DeleteRulesForUser
, но я не думаю, что это хорошо для производительности из-за того, что в BL иногда есть циклы for. Я также подумал, может, мне стоит переписать свой метод обновления, но пока не знаю, как это сделать.
Чтобы вы посоветовали?
К вашему сведению: у меня отключена функция LazyLoading.
Примечание. BL использует не классы EF, а собственные классы домена (поддержка EF была добавлена позже). Не критикуйте существующую архитектуру, я хочу решение этой проблемы как есть.
РЕДАКТИРОВАТЬ1: По мере того, как я читаю немного больше, возможно, AutoDetectChangesEnabled
может помочь, но мне нужно больше информации, чтобы узнать.