Эта проблема несколько раз обсуждалась в stackoverflow, однако я не смог найти ответа о том, как она была решена с использованием общего шаблона репозитория. Все данные ответы используют DBContext напрямую. В общем шаблоне репозитория у меня не будет прямого доступа к DBContext, также я использую Unity для IOC.
Итак, вот проблема: у меня есть родитель, а у родителя есть дочерняя коллекция. Я устанавливаю некоторые свойства для родителя, а также удаляю дочерний элемент из коллекции. Однако, когда я звоню SaveChanges()
, я получаю сообщение об ошибке
Операция завершилась неудачно: связь не может быть изменена, так как одно или несколько свойств внешнего ключа не могут принимать значения NULL. Когда в отношения вносятся изменения, для связанного свойства внешнего ключа устанавливается нулевое значение. Если внешний ключ не поддерживает значения NULL, необходимо определить новую связь, свойству внешнего ключа необходимо присвоить другое значение, отличное от NULL, или необходимо удалить несвязанный объект.
Теперь я не знаю, почему EF пытается установить для FK значение null вместо того, чтобы просто удалить запись. Какова цель установки FK на ноль, но сохранения потерянной записи в БД.
В любом случае, как мне решить эту проблему, используя шаблон репозитория? Нужно ли выставлять какой-либо новый метод из репозитория?
Объекты
public class parent
{
public int ParentID {get;set;} //Primary Key
public string ParentName {get;set}
public ICollection<Child> Children {get;set}
}
public class Child
{
public int ChildID {get;set;} //Primary Key
public string ChildName {get;set;}
public int ParentID {get;set;} //Foreign Key
}
Сервис
public class MyService
{
private IGenericRepository _repository;
public MyService(IGenericRepository repository)
{
_repository = repository;
}
public void UpdateParent(int parentID,string parentName, int[] sourceChildIDs)
{
var p = _repository.GetQuery<Parent>()
.Include(x => x.Children)
.Where(x => x.ParentID == parentID)
.SingleOrDefault();
p.ParentName = parentName;
var childrenToDetete = new List<Child>();
foreach (var child in p.Children)
{
if (!sourceChildIDs.Contains(child.ChildID))
{
childrenToDetete.Add(child);
}
}
foreach (var child in childrenToDetete)
{
p.Children.Remove(child);
}
_repository.SaveChanges(); // i get error here
}
}
Репозиторий
public class GenericRepository : IGenericRepository
{
private DbContext _dbContext;
public GenericRepository(DbContext dbContext)
{
if (dbContext == null)
{
throw new ArgumentNullException("dbContext");
}
_dbContext = dbContext;
}
public TEntity Create<TEntity>() where TEntity : class
{
return _dbContext.Set<TEntity>().Create<TEntity>();
}
public TEntity Add<TEntity>(TEntity entity) where TEntity : class
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
return _dbContext.Set<TEntity>().Add(entity);
}
public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
{
return _dbContext.Set<TEntity>();
}
public IQueryable<TEntity> GetQuery<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
return GetQuery<TEntity>().Where(predicate);
}
public void Delete<TEntity>(TEntity entity) where TEntity : class
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_dbContext.Set<TEntity>().Remove(entity);
}
public void Delete<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class
{
IEnumerable<TEntity> records = GetQuery<TEntity>(criteria);
foreach (TEntity record in records)
{
Delete<TEntity>(record);
}
}
public void Update<TEntity>(TEntity entity) where TEntity : class
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_dbContext.Entry(entity).State = EntityState.Modified;
}
public int SaveChanges()
{
return _dbContext.SaveChanges();
}
}