This issue has been discussed several time on stackoverflow however i couldn't find answer about how it has been solved using generic repository pattern. All the answers given are using DBContext directly. In generic repository pattern i will not have direct access to DBContext, also im using Unity for IOC.
So here is the issue: I have parent and parent has child collection. I am setting some properties on parent and also delete child from the collection. However when i call SaveChanges()
i get error
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
Now i dont know why EF is trying to set FK to null instead of just deleting the record. Whats the pupose of setting the FK to null but keeping the orphan record in DB.
Any way how do i solve this issue using repository pattern? Do i need to expose any new method from repository?
Entities
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
}
Service
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
}
}
Repository
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();
}
}