Хороший шаблон репозитория для asp.net mvc

Я реализовал шаблон репозитория в своем веб-приложении asp.net mvc... Но я хочу знать, хороший ли это шаблон репозитория, или я все же могу его улучшить...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using TaxiMVC.BusinessObjects;

namespace TaxiMVC.Models
{
    public class ClientRepository
    {
        private TaxiDataContext taxidb = new TaxiDataContext();
        Client cli = new Client();

        //Get all Clients
        public IQueryable<ClientBO> FindAllClients(int userId)
        {
            var client = from c in taxidb.Clients
                         where c.CreatedBy == userId && c.IsDeleted == 0 
                         select new ClientBO()
                         {
                             ClientId = c.ClientId,
                             ClientName= c.ClientName,
                             ClientMobNo= Convert.ToString(c.ClientMobNo),
                             ClientAddress= c.ClientAddress
                         };
            return client;
        }

        //Get Client By Id
        public ClientBO FindClientById(int userId,int clientId)
        {
            return (from c in taxidb.Clients
                    where c.CreatedBy == userId && c.ClientId == clientId && c.IsDeleted == 0
                         select new ClientBO()
                         {
                             ClientId = c.ClientId,
                             ClientName= c.ClientName,
                             ClientMobNo= Convert.ToString(c.ClientMobNo),
                             ClientAddress= c.ClientAddress
                         }).FirstOrDefault();
        }

        //Insert a new client
        public bool ClientInsert(ClientBO clientBO)
        {
            cli.ClientName = clientBO.ClientName;
            cli.ClientMobNo = Convert.ToInt64(clientBO.ClientMobNo);
            cli.ClientAddress = clientBO.ClientAddress;
            cli.CreatedDate = clientBO.CreatedDate;
            cli.IsDeleted = clientBO.IsDeleted;
            cli.CreatedBy = clientBO.CreatedBy;

            if (!taxidb.Clients.Where(c => c.ClientMobNo == cli.ClientMobNo).Any())
            {
                taxidb.Clients.InsertOnSubmit(cli);
                taxidb.SubmitChanges();
                return true;
            }
            else
                return false;
        }

      //Client Update
        public ClientBO updateClient(ClientBO clientBO)
        {
            var table = taxidb.GetTable<Client>();
            var cli = table.SingleOrDefault(c => c.ClientId == clientBO.ClientId && c.CreatedBy==clientBO.CreatedBy);
            cli.ClientName = clientBO.ClientName;
            cli.ClientMobNo = Convert.ToInt64(clientBO.ClientMobNo);
            cli.ClientAddress = clientBO.ClientAddress;
            taxidb.SubmitChanges();
            return clientBO;
        }

        //Delete Clients
        public bool deleteClients(string Ids, int userId)
        {
            var idsToDelete = Ids.Split(',').Select(c => Convert.ToInt32(c));
            var clientsToDelete = taxidb.Clients.Where(c => idsToDelete.Contains(c.ClientId));
            foreach (var client in clientsToDelete)
            {
                client.IsDeleted = Convert.ToByte(1); 
            }
            taxidb.SubmitChanges();
            return true;
        }
     }
}

и мой ClientBo.cs,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TaxiMVC.BusinessObjects
{
    public class ClientBO
    {
        public int ClientId { get; set; }
        public string ClientName { get; set; }
        public string ClientMobNo { get; set; }
        public string ClientAddress { get; set; }
        public DateTime CreatedDate { get; set; }
        public byte IsDeleted { get; set; }
        public int CreatedBy { get; set; }
    }
}

Я не реализовал IRepository здесь... Должен ли я реализовать его или мой репозиторий все еще можно улучшить... Любое предложение....


person ACP    schedule 19.07.2010    source источник
comment
Строго говоря, это не шаблон Repository. Вы можете прочитать больше здесь: fabiomaulo.blogspot.com/2009/ 09/   -  person griZZZly8    schedule 19.07.2010


Ответы (2)


Хм, определенно есть пара вещей, которые я бы сделал, чтобы улучшить это.

Во-первых: я бы определил интерфейс для реализации вашего репозитория. Это позволяет вам лучше контролировать зависимости, а в сочетании с инфраструктурой Inversion Of Control/Dependency Injection (IOC/DI) это значительно улучшается. Платформы IOC/DI включают StructureMap или NInjet. Прочтите это от Скотта Хансельмана, это довольно полный список.

Ваш интерфейс может выглядеть так:

public interface IClientRepository
{
    IQueryable<ClientBO> FindAllClients(int userId);
    ClientBO FindClientById(int userId, int clientId);
    ClientInsert(ClientBO clientBO);
    ClientBO updateClient(ClientBO clientBO);
    bool deleteClients(string Ids, int userId);
}

Во-вторых: не выполняйте преобразование вашего бизнес-объекта (ClientBO) в постоянный объект (Client) внутри вашего репозитория. Это означает, что если вы внесете какие-либо изменения в свой BO, вам нужно будет пройти и изменить весь репозиторий.

Я заметил, что у вас много кода присваивания влево-вправо, например.

cli.ClientName = clientBO.ClientName;

Я бы серьезно изучил использование AutoMapper. Это делает этот «код обезьяны» чертовски проще.

РЕДАКТИРОВАТЬ: Вот сообщение в блоге, в котором описывается, как использовать AutoMapper для удаления кода присваивания слева направо.

В-третьих: ваша структура именования распространена по всему магазину. У нас есть: FindAllClients(), ClientInsert(), updateClient() все в одном классе. Очень-очень неудачное именование. Для вашего репозитория попробуйте смоделировать свои методы на основе того, что будет происходить на стороне БД. Попробуйте Add или Insert, Delete, FindAll или GetAll, Find или GetAll, SaveChanges имена методов.

Не добавляйте/не добавляйте тип к имени метода, так как вы находитесь в ClientRepository, подразумевается, что вы будете добавлять или получать Client.

Четвертое: вы смешиваете синтаксис LINQ. В некоторых местах вы используете декларативный синтаксис запроса, а в других местах вы используете синтаксис метода. Выберите 1 и используйте его везде.

Пятое: меня беспокоит эта строка:

 if (!taxidb.Clients.Where(c => c.ClientMobNo == cli.ClientMobNo).Any())

Для меня это подозрительно похоже на бизнес-логику. Не то, что должно быть в репозитории. Либо объявите столбец UNIQUE в БД, либо переместите эту логику на другой уровень проверки.

Это были основные вещи, которые бросились мне в глаза. Пара из них является личным предпочтением, но я надеюсь, что это поможет.

person Alastair Pitts    schedule 19.07.2010
comment
@Alaistar +1 хороший ответ .. Но я не могу понять вашу вторую точку ... Можете ли вы обновить вторую точку с помощью ex automapper ... - person ACP; 19.07.2010
comment
Обновлено ссылкой на хороший пост в блоге, описывающий процесс. - person Alastair Pitts; 19.07.2010
comment
Хороший ответ, но я бы оспорил ваше мнение о синтаксисе LINQ. Нет ничего плохого в том, чтобы использовать прагматичный подход к определению операторов LINQ, записывайте их максимально понятным образом. - person David Neale; 19.07.2010
comment
@ Дэвид Нил, я лично думаю, что наличие нескольких вариантов синтаксиса LINQ в одном классе сбивает с толку, но я не мог этого понять. - person Alastair Pitts; 19.07.2010

Почему вы использовали строку для массива идентификаторов:

public bool deleteClients(string Ids, int userId)

Я думаю, вам следует использовать int[] или List<int>.

Также я бы написал список, но не IQueryable в FindAllClients.

public List<ClientBO> FindAllClients(int userId)

И, конечно, вы должны написать интерфейс IClientRepository, потому что это правильный подход в соответствии с принципами SOLID.

Если вы будете писать интерфейс, то вы можете написать другие классы, которые используют Repository с этим интерфейсом более гибко, примерно так:

public class ClientService : IClientService
{
    IClientRepository m_clientRepository;

    public ClientService(IClientRepository rep)
    {
        m_clientRepository = rep;
    }
}

И тогда вы сможете протестировать этот код с помощью Mock-класса IClientRepository, используя что-то вроде Moq. И, конечно же, если вы напишете другие IClientRepository (например, XmlClientRepository), вы измените инициализацию только того класса, который использует репозиторий.

Если вы используете ASP.NET MVC, вы сможете использовать IClientRepository в своем контроллере, и его будет легче тестировать.

Для более гибкого решения вы можете использовать шаблон IoC-контейнера (NInject, Unity).

Я надеюсь, что этот ответ поможет вам.

person Pavel Belousov    schedule 19.07.2010