0

Dieses Problem wurde in Stackoverflow mehrmals diskutiert, aber ich konnte keine Antwort finden, wie es mit dem generischen Repository-Muster gelöst wurde. Alle angegebenen Antworten verwenden DBContext direkt. Im generischen Repository-Muster habe ich keinen direkten Zugriff auf DBContext, auch nicht mit Unity für IOC.Entity Framework: Wie Kind mit generischen Repository-Muster löschen?

Also hier ist das Problem: Ich habe Eltern und Elternteil Kind Sammlung. Ich setze einige Eigenschaften auf Eltern und lösche auch Kind von der Ansammlung. Allerdings, wenn ich SaveChanges() i Fehler rufen erhalten

Der Vorgang ist fehlgeschlagen: Die Beziehung konnte nicht geändert werden, weil eine oder mehrere der Fremdschlüsseleigenschaften ist nicht-nullable. Wenn eine Änderung an einer Beziehung vorgenommen wird, wird die zugehörige Fremdschlüsseleigenschaft auf einen Nullwert festgelegt. Wenn der Fremdschlüssel keine Nullwerte unterstützt, muss eine neue Beziehung definiert werden, die Fremdschlüsseleigenschaft muss einen anderen Nicht-Null-Wert zugewiesen haben, oder das nicht verwandte Objekt muss gelöscht sein.

Jetzt weiß ich nicht, warum EF versucht, FK auf null zu setzen, anstatt nur den Datensatz zu löschen. Das ist die Aufgabe, den FK auf null zu setzen, aber den verwaisten Datensatz in der DB zu behalten.

Wie kann ich dieses Problem mit Repository-Muster lösen? Muss ich eine neue Methode aus dem Repository verfügbar machen?

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 
    } 

Dienst

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(); 
     }  
    } 

Antwort

0

Sie entfernen die Kinder von th e Eltern, aber nicht aus der Datenbank. Als Randbemerkung, können Sie dies in einer prägnanten Art und Weise tun:

foreach (var child in p.Children 
         .Where(child => !sourceChildIDs.Contains(child.ChildID)) 
         .ToList()) 
{ 
    p.Children.Remove(child); 
} 

Aber das bricht nur die Verbindung zwischen Eltern und Kindern. EF irrt auf der Seite der Vorsicht und geht davon aus, dass Sie nur die Fremdschlüssel-Referenz der Kinder entfernen, nicht die Kinder insgesamt entfernen möchten.

Also muss man die Kinder aus der Datenbank entfernen, indem die vorhergehenden Aussagen ersetzt durch

var delIds = p.Children.Where(child => !sourceChildIDs.Contains(child.ChildID)) 
         .Select(c => c.ChildID).ToList(); 
_repository.Delete<Child>(c => delIds.Contains(c.ChildID)); 

By the way, ist dies eine eher unüblich generische Repository-Implementierung. Normalerweise werden generische Repositories für einen Typ instanziiert, d. H. Die Definition wäre GenericRepository<T>. Instanzen dieser Repositorys teilen sich typischerweise eine Kontextinstanz, während sie in einer Arbeitseinheit zusammenarbeiten, die auch die Änderungen speichert.

+0

Ich glaube, ich habe noch berechnen DELID – LP13

+0

eine Zeile vergessen;) –

+0

Dank .. Wenn ich 'implementieren GenericRepository ' für jede Art, wie wollen Sie 'GenericRepository ' in 'MyService' injizieren. Dieser Dienst verfügt über mehrere Methoden und sollte in der Lage sein, beliebige Entitäten abzufragen. – LP13

Verwandte Themen