我想强制要求您每次与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帮助我找到了这个解决方案。
答案 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();
}
}
如果你给这个类一个接口,你也可以模拟它以进行单元测试。