ASP.NET MVC的好的存储库模式

3

我在我的Asp.net MVC Web应用程序中实现了存储库模式...但我想知道这是一个好的存储库模式还是我可以进一步改进它...

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... 我需要实现它吗?还是我的仓储库仍然可以改进... 有什么建议吗....

严格来说,这并不是“仓储”模式。 你可以在这里阅读更多内容: http://fabiomaulo.blogspot.com/2009/09/repository-or-dao-repository.html - griZZZly8
2个回答

15

嗯,我确实有几件事情可以做来改进这个。

首先:我会为您的存储库定义一个要实现的接口。这样可以更好地控制依赖关系,并且与反转控制/依赖注入(IOC/DI)框架配合使用时,效果会大大提高。IOC/DI框架包括StructureMap或NInjet。请阅读此处Scott Hanselman的文章,它是一个相当全面的列表。

您的接口可能如下所示:

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()全部在一个类中。非常非常糟糕的命名。对于你的存储库,请尝试根据在数据库端将发生的情况来建模你的方法。尝试使用AddInsertDeleteFindAllGetAllFindGetAllSaveChanges方法名称。
不要将类型附加/前置到方法名称中,因为你在ClientRepository中,暗示着你将添加或获取Client
第四点:你混合使用了LINQ语法。在某些地方,你使用了声明式查询语法,在其他地方,你使用了方法语法。选择1种并在所有地方使用它。
第五点:这一行让我担忧:
 if (!taxidb.Clients.Where(c => c.ClientMobNo == cli.ClientMobNo).Any())

这看起来非常像业务逻辑,不应该放在代码库中。要么在数据库中声明列为UNIQUE,要么将该逻辑移至另一个验证层中。
这些是我注意到的主要问题。其中有几个是个人偏好,但我希望这些能对你有所帮助。

1
@Alaistar +1 很好的回答.. 但是我不明白你的第二点... 你能否用一个 automapper 的例子来更新第二点... - ACP
更新了一个链接,指向一篇描述该过程的好博客文章。 - Alastair Pitts
好的回答 - 但我会对你关于LINQ语法的观点提出异议。在定义LINQ语句时采取务实的方法并没有什么问题,用最易懂的方式编写即可。 - David Neale
2
@David Neale,我个人认为在一个类中拥有多个LINQ语法变体会令人困惑,但我也能理解这种做法。 - Alastair Pitts

1
你为什么在 Id 数组中使用了字符串?
public bool deleteClients(string Ids, int userId)

我认为你应该使用int[]或者List<int>

此外,在FindAllClients中我会写List而不是IQueryable。

public List<ClientBO> FindAllClients(int userId)

当然,你应该编写接口IClientRepository,因为这是符合SOLID原则的正确方法。

如果你编写了接口,那么你可以编写其他使用此接口的存储库类,使其更加灵活,例如:

public class ClientService : IClientService
{
    IClientRepository m_clientRepository;

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

然后,您将能够使用类似Moq的东西来测试Mock-class IClientRepository的代码。当然,如果您编写其他IClientRepository(例如XmlClientRepository),您只需更改使用存储库的类的初始化。

如果您使用ASP.NET MVC,则可以在控制器中使用IClientRepository,这将使其更易于测试。

对于更灵活的解决方案,您可以使用IoC容器模式(NInject、Unity)。

我希望这个答案能帮到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接