2016-12-17 5 views
9

Ich versuche, ein generisches Repository mit Dapper zu erstellen. Ich habe jedoch einige Schwierigkeiten, die CRUD-Operationen zu implementieren.Generisches Repository mit Dapper

ist hier ein Code aus dem Repository:

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class 
{ 
    internal IDbConnection Connection 
    { 
     get 
     { 
      return new SqlConnection(ConfigurationManager.ConnectionStrings["SoundyDB"].ConnectionString); 
     } 
    } 

    public GenericRepository(string tableName) 
    { 
     _tableName = tableName; 
    } 

    public void Delete(TEntity entity) 
    { 
     using (IDbConnection cn = Connection) 
     { 

      cn.Open(); 
      cn.Execute("DELETE FROM " + _tableName + " WHERE [email protected]", new { ID = entity.Id }); 
     } 
    } 
} 

Wie Sie sehen können, meine Lösch-Methode einen TEntity als Parameter annimmt, die ein Paramter der Typklasse ist.

Ich nenne meine Delete-Methode von meinem UserRepository wie folgt aus:

public class UserRepository : GenericRepository<User>, IUserRepository 
{ 
    private readonly IConnectionFactory _connectionFactory; 

    public UserRepository(IConnectionFactory connectionFactory) : base("User") 
    { 
     _connectionFactory = connectionFactory; 
    } 

    public async Task<User> Delete(User model) 
    { 
     var result = await Delete(model); 
     return result; 
    } 
} 

Die Sache ist, dass ich nicht entity.Id in meiner Delete-opration in meinem generic Repository schreiben kann. Ich bekomme einen Fehler. Wie kann ich CRUD-Operationen so einfach umsetzen?

Hier ist die Fehlermeldung:

TEntity does not contain a definition of "Id" and no extension method "Id" accepting a argument of type "TEntity" could be found 
+0

Wenn Sie einen Fehler haben und eine Frage zu diesem Fehler stellen, müssen Sie diesen Fehler einfügen. Ein Fehler, der zur Laufzeit in diesem Fall auftritt, wird als 'Exception' bezeichnet (* so manifestieren sich Fehler in .net *). Fügen Sie die 'Message', den' Type', den 'StackTrace' hinzu und wiederholen Sie dies rekursiv über' InnerException'. Verwenden Sie den Bearbeitungslink zu Ihrer Frage, um dieses Detail einzubeziehen, und schließen Sie es nicht als Kommentar ein.Bitte lesen Sie auch [Wie stelle ich eine gute Frage] (http://stackoverflow.com/help/how-to-ask). – Igor

+0

@Igor: Es ist kein Laufzeitfehler. Überprüfen Sie meine aktualisierte Frage. – Bryan

+0

Haben alle Typen, die Sie verwenden können, eine öffentliche Eigenschaft vom Typ 'int' namens' Id'? – Igor

Antwort

7

Definieren Sie eine Schnittstelle wie folgt.

public interface ITypeWithId { 
    int Id {get;} 
} 

Und stellen Sie sicher, dass Ihr User Typ diese Schnittstelle implementiert.

Jetzt wenden Sie es als generische Einschränkung auf Ihre Klasse an.

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class, ITypeWithId 

Wenn Sie Typen, die im Repository gespeichert sind, aber keine ID Eigenschaft haben, dann löschen Typeinschränkung spezifisch für das Verfahren und nicht die Klasse. Auf diese Weise können Sie den gleichen Repository-Typ auch mit Typen verwenden, die auf etwas anderes wie eine Zeichenfolge oder einen zusammengesetzten (Multi-) Schlüssel zugreifen können.

public void Delete<T>(T entity) where T : class, ITypeWithId 
{ 
    using (IDbConnection cn = Connection) 
    { 

     cn.Open(); 
     cn.Execute("DELETE FROM " + _tableName + " WHERE [email protected]", new { ID = entity.Id }); 
    } 
} 
+0

Vielen Dank :). Also, wenn ich einen Benutzer mit Benutzernamen erhalten möchte, sollte ich diese Abfrage in meinem UserRepository anstelle des Generic-Repository tun? – Bryan

+0

@Bryan - Wenn Sie spezifische Operationen für die Entität haben, die nicht generisch sind, sollten sie in den abgeleiteten Repository-Typen wie 'UserRepository' enthalten sein. In Ihrem GenericRepository können nur allgemeine Operationen definiert werden. – Igor

+0

Danke. Und muss meine User-Klasse die von Ihnen bereitgestellte Schnittstelle implementieren? Die Benutzerklasse ist die Entität – Bryan

1

Sie haben eine Schnittstelle wie unter

definieren
public interface IIdentityEntity 
{ 
    public int Id { get; set;} 
} 

alle Einheiten, die die Klasse verwenden möchten, müssen die IIdentityEntity implementieren.

und die erste Zeile sollte auf die folgende

und was das Problem ist, geändert werden, dass Sie nur die TEntity als Klasse und Klasse beschrieben haben keine Id in der Beschreibung so benachrichtigen Sie müssen Compiler, der vom generischen Typ eine Schnittstelle implementiert hat, die ein Id-Feld enthält

+0

Also muss meine User-Klasse diese Schnittstelle implementieren? – Bryan

+0

alle Klassen, die das generische Löschen verwenden möchten, müssen die Schnittstelle implementieren – Khatibzadeh

2

Bitte tun Sie das nicht! Ihr generisches Repository fügt mehr Verwirrung als Wert hinzu. Es ist ein fragiler Code (String-Literale für _tableName, ungültige Cast-Fehler im ID-Parameter) und führt zu einer klaffenden Sicherheitslücke (SQL-Injektion über _tableName). Wenn Sie sich für Dapper entschieden haben, liegt das daran, dass Sie die Kontrolle über Ihren SQL-Server haben möchten. Es macht also keinen Sinn, den SQL-Server zu generieren, den Sie an Dapper senden.

Verwandte Themen