EF4 存储库模式在将存储库注入服务时出现问题。似乎无法正确处理

发布于 2024-10-07 07:26:37 字数 2711 浏览 2 评论 0原文

我发现很难测试 EntityFramework 4 。我使用数据库优先方法来使用它,现在转向 poco 太晚了。需要快速交付,没有时间像往常一样正确学习。

我已经使用工作单元实现了存储库模式,但我发现很难将存储库注入到我的服务层中,以便我可以在不访问数据库的情况下测试我的业务层服务、验证等的行为。 但我遇到了很多小问题。

  1. 为了将存储库注入到服务(构造函数)中,调用层需要引用 DAL(EF 实体)。我不想要这个

  2. 如果我有很多存储库 EG CustomerRepository 、EmployeeRepository ,那么我需要有与存储库一样多的构造函数,以便我可以注入存储库。

    3.不知道该去哪里。我在网上没有找到任何使用 EF4 将存储库注入到服务中的示例。我见过的所有示例都自行模拟存储库,这对我来说不好。

我需要在不访问数据库的情况下测试我的服务层/BizLayer。

所有的事情都是不可测试的,并且增加了很多依赖项和问题。

我已经放在一起的 Noddy 示例

public class DepartmentServiceLibrary
{
    private readonly IDepartmentRepository _departmentRepository;

    public DepartmentServiceLibrary(IDepartmentRepository  departmentRepository)
    {
        _departmentRepository = departmentRepository;
    }

    public List<DepartmentDto> GetDepartments()
    {
        return DeparmentBiz.GetDepartments();
    }

    private DeparmentBL _departmentBiz;
    private DeparmentBL DeparmentBiz
    {
        get
        {
            return _departmentBiz ?? new DeparmentBL(_departmentRepository);
        }
    }
}

//internal class

internal class DeparmentBL
{
    private readonly IDepartmentRepository _departmentRepository;

    public DeparmentBL(IDepartmentRepository departmentRepository)
    {
        _departmentRepository = departmentRepository;
    }

    public List<DepartmentDto> GetDepartments()
    {
        using (var ctx = new AdventureWorksContext())
        {
            var uow = new UnitOfWork(ctx);
            _departmentRepository.UnitOfWork = uow;
            var query = _departmentRepository.GetAll();

            return query.Select(dpt => new DepartmentDto
                                           {
                                               DepartmentId = dpt.DepartmentID,
                                               Name = dpt.Name,
                                               GroupName = dpt.GroupName
                                           }).ToList();
        }
    }
}

下面的 TestMethod 要求我向 dal 添加一个引用,这违背了要点 有

    [TestMethod]
    public void Should_be_able_to_call_get_departments()
    {
        var mock = new Mock<IDepartmentRepository>();
        var expectedResult = new List<Department>();  //Dependency to DAL as Department is a EF Entity generated by EF.

        mock.Setup(x => x.GetAll()).Returns(expectedResult);
        var companyService = new MyCompanyBL(mock.Object);  //InternalVisibileTO
        var departments = companyService.GetAll();
        //assert removed for brevity

任何建议或示例显示如何做到这一点吗? 谢谢

    }

I am finding difficult to test EntityFramework 4 .I am using it using the database first approach,too late now to move to poco.Needed to deliver pretty quickly,no time to learn properly as usual.

I have implemented the repository pattern with unit of work but I am finding difficult to inject a repository into my Service layer so that I can test the behaviour of my business layer service ,validation etc... without hitting the db.
but I am incurring in many little problems.

  1. In order to inject the Repository into the service(constructor) the calling layer need to have a reference to the DAL (EF Entities) . I dont want this

  2. If i have many repositories EG CustomerRepository ,EmployeeRepository than I need to have as many constructors as repositories so that I can inject the repository.

    3.Not sure where to go from here. I have not found any example on the net where they inject the repository into the service using EF4. All the examples I have seen they mock the repository on it's own,which is not good to me.

I need to test my service layer/BizLayer without hitting the database.

The all thing is just not testable and adds so many dependencies and problems.

Noddy example I have put together

public class DepartmentServiceLibrary
{
    private readonly IDepartmentRepository _departmentRepository;

    public DepartmentServiceLibrary(IDepartmentRepository  departmentRepository)
    {
        _departmentRepository = departmentRepository;
    }

    public List<DepartmentDto> GetDepartments()
    {
        return DeparmentBiz.GetDepartments();
    }

    private DeparmentBL _departmentBiz;
    private DeparmentBL DeparmentBiz
    {
        get
        {
            return _departmentBiz ?? new DeparmentBL(_departmentRepository);
        }
    }
}

//internal class

internal class DeparmentBL
{
    private readonly IDepartmentRepository _departmentRepository;

    public DeparmentBL(IDepartmentRepository departmentRepository)
    {
        _departmentRepository = departmentRepository;
    }

    public List<DepartmentDto> GetDepartments()
    {
        using (var ctx = new AdventureWorksContext())
        {
            var uow = new UnitOfWork(ctx);
            _departmentRepository.UnitOfWork = uow;
            var query = _departmentRepository.GetAll();

            return query.Select(dpt => new DepartmentDto
                                           {
                                               DepartmentId = dpt.DepartmentID,
                                               Name = dpt.Name,
                                               GroupName = dpt.GroupName
                                           }).ToList();
        }
    }
}

The following TestMethod requires me to add a ref to the dal which defeats the point

    [TestMethod]
    public void Should_be_able_to_call_get_departments()
    {
        var mock = new Mock<IDepartmentRepository>();
        var expectedResult = new List<Department>();  //Dependency to DAL as Department is a EF Entity generated by EF.

        mock.Setup(x => x.GetAll()).Returns(expectedResult);
        var companyService = new MyCompanyBL(mock.Object);  //InternalVisibileTO
        var departments = companyService.GetAll();
        //assert removed for brevity

Any suggestions or examples out there that shows how to do it?
thanks

    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

未蓝澄海的烟 2024-10-14 07:26:37

简短的答案是 - 因为您没有使用 POCO,所以您的所有层都将引用您的 DAL。

如果没有 POCO,您可以使用代码生成,这意味着 EF 在 Model.edmx.designer.cs 文件中创建模型类。

一个选项(还没有尝试过 - 我突然想到)是将 EF 实体手动投影到 DTO 中。

因此,您的存储库可能会这样做:

public List<OrderDTO> GetOrdersForCustomer(int customerId)
{
   return _ctx.Orders
        .Where(x => x.CustomerId == customerId)
        .ToList()
        .Select(x => new OrderDTO { // left to right copy });
}

OrderDTO 类可能位于存储库以及您的其他项目引用的单独程序集中。因此其他项目将在 DTO 程序集上工作,并且不需要对存储库的引用。

但在这里,你要投影到任何地方的类中(基本上是进行 POCO,但手动进行,并且需要更多工作)从左到右复制属性 - 非常痛苦。

然而,这是一个选择。

老实说 - 迁移到 POCO 并不需要很长时间

有一个 T4 模板可以为您生成 POCO - 您可以在几分钟内启动并运行。

由于您已经在使用依赖项注入和存储库,因此您应该硬着头皮更改为 POCO,或者保留对 DAL 的引用。

The short answer is - since you're not using POCOs, all your layers will have a reference to your DAL.

Without POCOs, you use code generation, which means EF creates the model classes in the Model.edmx.designer.cs file.

An option (haven't tried this - off the top of my head) is to manually project the EF entities into DTOs.

So your Repository might do this:

public List<OrderDTO> GetOrdersForCustomer(int customerId)
{
   return _ctx.Orders
        .Where(x => x.CustomerId == customerId)
        .ToList()
        .Select(x => new OrderDTO { // left to right copy });
}

The OrderDTO class could be in a separate assembly, which the repository references, as well as your other projects. So the other projects would work off the DTO assembly, and wouldn't require a reference to the Repository.

But here you're projecting into classes everywhere (basically doing POCO, but manually, and with more work) left to right copying of properties - very painful.

However, that is an option.

Honestly - it does not take long to move to POCOs.

There is a T4 template which will generate the POCOs for you - you could be up and running in a matter of minutes.

And since you're already using dependency injection and repository, you should either bite the bullet and change to POCOs, or keep the reference to the DAL.

不可一世的女人 2024-10-14 07:26:37

类似的代码可以在 GitHub 中看到
详细说明可以在 TechNet

Something similar in terms of code can be seen here in GitHub
and detail explanation can be found in TechNet

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文