簡體   English   中英

實體框架單元測試(或類似測試),以確保在使用DbSet時始終調用特定的擴展方法

[英]Entity Framework unit test (or similar) to ensure that when using a DbSet, an particular extension method is always called

我要強制執行一項要求,即與db.Users進行交互的任何時候都必須調用特定的擴展方法。 以下是一些更具體的信息。

通過實體框架與數據庫交互時,我有以下查詢(db是DbContext實例):

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

該查詢在整個應用程序中會一直變化(WHERE子句通常會有所不同,等等)。 因此,我想要求您必須始終調用FromOrganisation()擴展方法,以便首先由Organization過濾返回的所有數據。

這是為了防止任何人看到屬於不同組織的數據,但我始終堅持如何實現它。

我是否可以編寫單元測試來提醒開發人員使用用戶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方法按組織返回經過篩選的Users列表。 可以像往常一樣進一步過濾,合並和查詢等。

如果需要,您還可以訪問UsersUnfiltered DbSet,但是如果使用它,則會生成編譯器警告。 您可以通過在#pragma warning disable 618指令內部訪問它來禁止顯示此警告。

有了這個適當的位置,您便擁有了代碼,可防止您不按組織過濾就使用用戶數據,除非您確實打算這樣做。

感謝@mark_h幫助我達成此解決方案。

您提出的一個問題是,如果您可以強制使用它,那么即使您從上下文進行了初始查詢后,每次想要對一組用戶進行子查詢時,都必須強制執行它。

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();
    }
}

如果為此類提供了接口,則也可以出於單元測試的目的而對其進行模擬。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM