2

我目前正在开发一个 ASP .NET MVC 3 Web 应用程序作为原型,其中 Code First 作为数据访问层。现在我有点困惑把我的代码放在哪里。

我有一个班级客户和一个班级项目。项目对其客户具有导航属性。

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Project
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Customer Customer { get; set; }
}

我使用这两个类通过 codefirst 进行数据访问。

public class MyContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Project> Projects { get; set; }
}

我了解到,最好不要直接在我的 MVC 视图中使用这些数据访问类 - 所以我为单个客户创建了一个 ViewModel (CustomerListModel) 和一个 DTO。

public class CustomerDto
{        
    public int Id { get; set; }
    public string Name { get; set; }
    public int ProjectCount { get; set; } <== this property is in question
}

public class CustomerListModel
{
    public List<CustomerDto> Customers;
}

在我的控制器中,我从进行实际数据访问的(服务)类中获取客户。

public class CustomerService : IDisposable
{
    private MyContext db;
    public CustomerService()
    {
        db = new MyContext();
    }

    public IEnumerable<Customer> GetAllCustomers()
    {
        return db.Customers.ToList<Customer>();
    }
}

在我的控制器中,我调用该方法来获取所有客户。

    public ViewResult Index()
    {
        //Mapper.CreateMap<Customer, CustomerDto>();

        var customerList = new List<CustomerDto>();
        foreach (var customer in rep.GetAllCustomers())
        {
            var cust = new CustomerDto();
            cust.Id = customer.Id;
            cust.Name = customer.Name;
            cust.Rate = customer.Rate;
==> cust.ProjectCount = customer.ProjectCount; <=====
            customerList.Add(cust);
        }

        var viewModel = new CustomerListModel()
        {                
            Customers = customerList //Mapper.Map<IEnumerable<Customer>, List<CustomerDto>>(rep.GetAllCustomers())
        };
        return View(viewModel);            
    }

我要问的是 - 例如将单个客户的 ProjectCount 放在哪里。我可以把它放在客户类

    public int ProjectCount
    {
       var db = new MyContext();
       return db.Projects.Where(x => x.Customer.Id == this.Id).Count();
    }

...但是我将有两个可以访问数据的地方-服务类和客户类。

我也可以将此代码放在我的 ServiceClass 中:

    public int GetProjectCount(Customer customer)
    {
        return db.Projects.Where(x => x.Customer.Id == customer.Id).Count();
    }

...但后来我不得不从控制器调用它:

        foreach (var customer in rep.GetAllCustomers())
        {
            var cust = new CustomerDto();
            cust.Id = customer.Id;
            cust.Name = customer.Name;
            cust.Rate = customer.Rate;
            cust.ProjectCount = rep.GetProjectCount(customer); <==
            customerList.Add(cust);
        }

...我也可以从客户类的吸气剂中从我的服务类中调用此方法。

    public int ProjectCount
    {
        get
        {
            return new CustomerService().GetProjectCount(this);
        }
    }

所有描述的方法都有效并给了我正确的结果 -我想以正确的方式做 - 你会怎么做 - 或者我完全偏离了轨道;-)?

谢谢!

4

1 回答 1

3

以下是我的看法,只是为了回顾一下我在评论中写的内容。我不能说这是否是“要走的路”,但我想认为这是一个可行的解决方案。

因此,如果您使用非泛型方法(正如我所提到的),对于具有少量表的小型数据库来说,这种方法简单、易于管理和调试,您可以按以下方式进行操作:

public interface ICustomerService
{
    IEnumerable<Customer> GetAllCustomers();
    // and other methods you'd like to use
}

public sealed class CustomerService : ICustomerService
{
    private YourContext context = new YourContext();
    // or, alternatively, even something along these lines
    private YourContext context;
    public CustomerService()
    {
        context = ContextFactory.GetDBContext();
    }
    //----

    public IEnumerable<Customer> GetAllCustomers()
    {
         // here goes the implementation
    }
}

public class YourController : Controller
{
    private ICustomerService customerService;
    public YourController(ICustomerService service)
    {
          customerService = service;
    }
    // and now you can call customerService.GetAllCustomers() or whatever other methods you put in the interface. 
}

题外话 - 数据库上下文工厂可能看起来像这样,以防您想稍后更改数据库连接:

public static ContextFactory
{
    public static YourContext GetDBContext()
    {
         return new YourContext();
    }        
}

当然,这种简单的设置适用于任何选择的 IoC 容器,我的是用于 Web 应用程序的 Autofac,它位于 Global.asax 中Application_Start

var builder = new ContainerBuilder();
    builder.Register(service => new CustomerService()).As<ICustomerService>().InstancePerHttpRequest();
    builder.RegisterControllers(typeof(MvcApplication).Assembly);
    var container = builder.Build();
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

依赖注入使以后测试控制器变得更容易,因为您可以使用许多模拟助手之一来模拟任何(例如准备好的项目列表)的数据库访问。

但是,如果您的大多数存储库的方法都相似,您可能想看看更通用的解决方案(它适用于数据库优先,但也可以应用于代码优先),这将更适合您的需求所以您不必重复代码,但是 - 代码可能看起来有点复杂。:)

于 2012-05-11T12:51:44.420 回答