2016-12-17 2 views
9

Im пытается создать общий репозиторий с dapper. Однако у меня есть некоторые трудности с реализацией CRUD-операций.Общий репозиторий с dapper

Вот код из репозитория:

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

Как вы можете видеть, мое удаление-метод принимает TEntity в качестве параметра, который является класс параметром Я типа.

Звоню Delete-метод из моего UserRepository так:

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

Дело в том, что я не могу написать entity.Id в моем Delete-OPRATION в моем родовом хранилище. Я получаю сообщение об ошибке. Итак, как я могу легко реализовать CRUD-операции, подобные этому?

Вот сообщение об ошибке:

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

Если у вас есть ошибка, и вы задаете вопрос об этой ошибке, вам необходимо включить эту ошибку. Ошибка, возникающая во время выполнения в этом случае, называется «Исключение» (* это то, как ошибки проявляются в .net *). Включите 'Message',' Type', 'StackTrace' и повторите это рекурсивно через' InnerException' до конца. Используйте ссылку редактирования на свой вопрос, чтобы включить эту деталь, не включайте ее в качестве комментария.Также прочитайте [Как задать хороший вопрос] (http://stackoverflow.com/help/how-to-ask). – Igor

+0

@Igor: Это не ошибка времени выполнения. Проверьте мой обновленный вопрос. – Bryan

+0

У всех типов, доступных для использования, есть общедоступное свойство типа 'int' с именем' Id'? – Igor

ответ

7

Определите интерфейс, подобный этому.

public interface ITypeWithId { 
    int Id {get;} 
} 

И убедитесь, что ваш User тип реализует этот интерфейс.

Теперь примените его к вашему классу в качестве общего ограничения.

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

Если у вас есть типы, которые хранятся в хранилище, но не имеют свойство Id затем сделать ваш удалить тип ограничения специфичные для метода, а не класс. Это позволит вам по-прежнему использовать один и тот же тип репозитория даже с типами, которые могут использоваться для чего-то другого, например, для строки или составной (мульти) клавиши.

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

Спасибо :). Итак, если я хочу получить пользователя по имени пользователя, я должен сделать этот запрос в моем UserRepositor вместо Generic-repository? – Bryan

+0

@Bryan. Если у вас есть определенные операции с объектом, которые не являются общими, они должны быть включены в производные типы репозитория, такие как 'UserRepository'. В вашем GenericRepository могут быть определены только общие операции. – Igor

+0

Спасибо. И должен ли мой пользовательский класс реализовать интерфейс, который вы предоставили? Пользовательский класс - это объект – Bryan

1

вы должны определить интерфейс, как показано ниже

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

все ваши лица, которые хотят использовать класс, необходимо реализовать IIdentityEntity.

и первая строка должна быть изменена следующим

и в чем была проблема в том, что вы описали только TEntity как класс и класс не имеет Id в его описании, так что вы должны уведомить компилятор, что тип Generic реализовал интерфейс, в котором есть поле Id внутри него.

+0

Итак, мой пользовательский класс должен реализовать этот интерфейс? – Bryan

+0

все классы, которые хотят использовать общий delete, должны реализовать интерфейс – Khatibzadeh

2

Пожалуйста, не делайте этого! Ваш общий репозиторий добавляет больше путаницы, чем значения. Это хрупкий код (строковые литералы для _tableName, недопустимые литые ошибки в параметре id) и вводит зияющее отверстие безопасности (SQL-инъекция через _tableName). Если вы выбрали Dapper, это потому, что вы хотите контролировать свой sql, поэтому нет смысла генерировать SQL-код, который вы отправляете Dapper.

Смежные вопросы