2016-01-21 9 views
8

ich eine Datenbank implementiert haben soft löschen (ein boolesches Flag, die Einträge als gelöscht markiert) mit dem folgenden Tutorial: http://www.codeguru.com/csharp/csharp/soft-deleting-entities-cleanly-using-entity-framework-6-interceptors.htmlEntity Framework soft löschen Implementierung mit Datenbank-Abfangjäger nicht funktioniert

Es mir da einmal eine sehr gute Umsetzung scheint eingerichtetes Löschen wird auf ein Modell angewendet, indem einfach eine [SoftDelete("IsDeleted")] Annotation hinzugefügt wird. Das Problem ist so weit, dass es nicht funktioniert.

Die Quelle scheint zuverlässig zu sein, und sie veröffentlichte auch ein Beispiel für ihre Lösung: https://github.com/rakeshbabuparuchuri/EFExpensionPoints

Können Sie einen Blick auf meinem Code in Fall haben ich falsch gemacht hätte etwas bei der Anwendung des weichen mein Projekt löschen?

Dies ist das Modell:

[SoftDelete("IsDeleted")] 
public class BC_Instance 
{ 
    public int ID { get; set; } 
    public bool IsDeleted { get; set; } 
} 

ApplicationDbContext.cs:

namespace bcplatform2.Models 
{ 
    public class ApplicationDbContext : IdentityDbContext<ApplicationUser> 
    { 
     public ApplicationDbContext() 
      : base("DefaultConnection", throwIfV1Schema: false) 
     { 
     } 

     // Add a DbSet for each one of your Entities 
     //public DbSet<VirtualGuest> VirtualGuests { get; set; } 
     public DbSet<BC_Instance> BiocloudInstances { get; set; } 

     static ApplicationDbContext() 
     { 
      Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer()); 
     } 

     public static ApplicationDbContext Create() 
     { 
      return new ApplicationDbContext(); 
     } 

     protected new void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      var conv = new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
       "SoftDeleteColumnName", 
       (type, attributes) => attributes.Single().ColumnName); 

      modelBuilder.Conventions.Add(conv); 
     } 
    } 
} 

ApplicationDbConfiguration.cs

SoftDeleteAttribute.cs:

namespace bcplatform2.Helpers 
{ 
    public class SoftDeleteAttribute : Attribute 
    { 
     public SoftDeleteAttribute(string column) 
     { 
      ColumnName = column; 
     } 

     public string ColumnName { get; set; } 

     public static string GetSoftDeleteColumnName(EdmType type) 
     { 
      MetadataProperty annotation = type.MetadataProperties 
       .Where(p => p.Name.EndsWith("customannotation:SoftDeleteColumnName")) 
       .SingleOrDefault(); 

      return annotation == null ? null : (string)annotation.Value; 
     } 
    } 
} 

SoftDeleteInterceptor.cs

Ich bemerkte, dass SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.VariableType.EdmType) nicht das weiche Lösch Attribut nicht finden und gibt null zurück. Aber ich weiß nicht warum.

namespace bcplatform2.Helpers 
{ 
    public class SoftDeleteInterceptor : IDbCommandTreeInterceptor 
    { 
     public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext) 
     { 
      if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace) 
      { 
       var queryCommand = interceptionContext.Result as DbQueryCommandTree; 
       if (queryCommand != null) 
       { 
        var newQuery = queryCommand.Query.Accept(new SoftDeleteQueryVisitor()); 
        interceptionContext.Result = new DbQueryCommandTree(
         queryCommand.MetadataWorkspace, 
         queryCommand.DataSpace, 
         newQuery); 
       } 

       var deleteCommand = interceptionContext.OriginalResult as DbDeleteCommandTree; 
       if (deleteCommand != null) 
       { 
        var column = SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.VariableType.EdmType); 
        if (column != null) 
        { 
         var setClauses = new List<DbModificationClause>(); 
         var table = (EntityType)deleteCommand.Target.VariableType.EdmType; 
         if (table.Properties.Any(p => p.Name == column)) 
         { 
          setClauses.Add(DbExpressionBuilder.SetClause(
            DbExpressionBuilder.Property(
             DbExpressionBuilder.Variable(deleteCommand.Target.VariableType, deleteCommand.Target.VariableName), 
             column), 
            DbExpression.FromBoolean(true))); 
         } 

         var update = new DbUpdateCommandTree(
          deleteCommand.MetadataWorkspace, 
          deleteCommand.DataSpace, 
          deleteCommand.Target, 
          deleteCommand.Predicate, 
          setClauses.AsReadOnly(), 
          null); 

         interceptionContext.Result = update; 
        } 
       } 
      } 
     } 
    } 
} 

IdentityConfig.cs

public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext> 
{ 
    protected override void Seed(ApplicationDbContext context) 
    { 
     InitializeIdentityForEF(context); 
     base.Seed(context); 
    } 

    //Create [email protected] with [email protected] in the Admin role   
    public static void InitializeIdentityForEF(ApplicationDbContext db) 
    { 
     //Initialize users and roles... 
    } 
} 

Antwort

7

Es ist ein Fehler in ApplicationDbContext.cs:

protected new void OnModelCreating(DbModelBuilder modelBuilder) {...} 

Du „neuen“ statt „überschreiben“ können Sie so OnModelCreating nie ausgeführt wird (versuchen Sie einen Breakpoint hinzufügen, um es zu überprüfen). So wird AttributeToTableAnnotationConvention niemals ausgeführt und Entitätsanmerkungen werden nie hinzugefügt.

Ändern es zu

protected override void OnModelCreating(DbModelBuilder modelBuilder) {...} 

wird es

+0

Wenn ich überschreibe, wird das ursprüngliche OnModelCreating nicht aufgerufen und das sollte nicht der Fall sein. 'new' andererseits lässt beide Methoden aufrufen. – nest

+0

Das ist nicht korrekt. Sie sollten überschreiben und dann base.OnModelCreating aufrufen, um an die Standardmethode zu delegieren (falls Sie dies wünschen). Setzen Sie einfach einen Haltepunkt in der aktuellen Methode und testen Sie, ob es stoppt, Sie werden sehen, dass es nicht funktioniert. – tede24

+0

@ tede24 ist richtig! –

1

Nun, scheint Sie Code zu mir. Vielleicht gibt es einen kleinen Fehler, der deine App kaputt macht. Man könnte dies versuchen:

  1. Entfernen Sie die SoftDeleteAttribute von BC_Instance

  2. bearbeiten die OnModelCreating Methode

    AttributeToTableAnnotationConvention<SoftDeleteAttribute, string> conv = 
        new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
         "SoftDeleteColumnName", 
         (type, attributes) => attributes.Single().ColumnName); 
    
    modelBuilder.Conventions.Add(conv); 
    //this will dynamically add the attribute to all models 
    modelBuilder.Types().Configure(delegate(ConventionTypeConfiguration i) 
    { 
        i.HasTableAnnotation("SoftDeleteColumnName", Entity.G etSoftDeleteColumnName()); 
    }); 
    
  3. ApplicationDbConfiguration Klasse

  4. bearbeiten den Kontext des Konstruktor

    löschen
    public ApplicationDbContext() 
        : base("DefaultConnection", throwIfV1Schema: false) 
    { 
        DbInterception.Add(new SoftDeleteInterceptor()); 
    } 
    

Hoffe, das hilft!

+0

Danke für Ihre Hilfe arbeiten. Ein Problem: in Zeile 'i.HasTableAnnotation (" SoftDeleteColumnName ", Entity.GetSoftDeleteColumnName()); '->' Der Name 'Entity existiert nicht im aktuellen Kontext'. – nest

+0

Außerdem, wie soll ich überprüfen, ob es funktioniert. Wenn ich die Datenbank direkt abfrage, sollte ich die Deleter-Datensätze richtig sehen? Der Interceptor wird nur auf den Code angewendet? – nest

+0

In meinem Fall ist Entity eine Basisklasse, die von den Modellen geerbt wird –