实体框架单元测试(或类似)以确保在使用DbSet时,始终调用特定的扩展方法

时间:2016-05-13 15:09:30

标签: c# entity-framework unit-testing

我想强制要求您每次与db.Users交互时都需要调用特定的扩展方法。以下是一些更具体的信息。

通过Entity Framework与我的数据库交互时,我有以下查询(db是DbContext实例):

var user = db.Users
              .FromOrganisation(someId)
              .FirstOrDefault(u => u.Username == someUsername);

此查询将在整个应用程序中的所有时间都有所不同(WHERE子句通常会有所不同等)。因此,我希望您必须始终调用FromOrganisation()扩展方法,以便返回的所有数据首先由Organization过滤。

这是为了防止任何人看到属于不同组织的数据,但我仍然坚持如何实现它。

我是否可以编写一个单元测试来提醒开发人员正在使用Users DbSet而不按组织过滤?如果没有,是否有任何替代路线可以达到相同的保护水平。

如果它很重要,扩展方法本身如下:

public static IQueryable<User> FromOrganisation(this IQueryable<User> u, int organisationId)
{
    return u.Where(x => x.OrganisationId == organisationId);
}

我的最终解决方案

我改变了我的上下文:

public DbSet<User> Users { get; set; }

变成了:

[Obsolete("MUST use service!")]
public DbSet<User> UsersUnfiltered { get; set; }


public IQueryable<User> Users(int id)
{
    #pragma warning disable 618
    return UsersUnfiltered.Where(x => x.OrganisationId == id);
    #pragma warning restore 618
}

这样做是为了鼓励您使用Users方法按组织返回已过滤的用户列表。这可以像往常一样进一步过滤,加入和查询等。

如果需要,您还可以访问UsersUnfiltered DbSet,但如果您使用它,则会生成编译器警告。您可以通过在#pragma warning disable 618指令中访问它来禁止此警告。

有了这个,您可以使用代码来防止您使用用户数据而不按组织过滤,除非您真的想要这样做。

感谢@mark_h帮助我找到了这个解决方案。

1 个答案:

答案 0 :(得分:0)

您提出的问题是,如果您可以强制使用它,那么即使您已经从上下文完成初始查询后,每次想要对一组用户进行子查询时也必须强制执行它,即< / p>

var allUsersOfOrganisation1 = db.Users.FromOrganisation(1)
// some code...
var someUsersOfOrganisation1 = allUsersOfOrganisation1.FromOrganisation(1).Where(...)

如果您强制使用扩展方法,您如何区分查询到包含所有用户的集合和已过滤的子集?

您可以通过包装实体模型并仅通过强制执行唯一组织ID的方法公开用户来实现您所获得的结果;

public class WrappedEntities
{
    private MyEntityFramework Entities = new MyEntityFramework();

    //regular public entities
    public DbSet<Organisation> Organisations { get { return Entities.Organisation; } set { Entities.Organisation = value as DbSet<Organisation>; } }

    //Special case
    public IQueryable<User> Users(int id)
    {
        return Entities.Users.Where(x => x.OrganisationId == organisationId);
    }

    //other wrapped methods...
    public int SaveChanges()
    {
        return Entities.SaveChanges();
    }
}

如果你给这个类一个接口,你也可以模拟它以进行单元测试。