2012-03-01 61 views
2

中擴展具有功能的實體模型是否合法,首先這是我的情況。我正在使用ASP.NET MVC 3和Entity Framework 4.1編寫Intranet應用程序。我的應用程序是使用「工作單元」和「存儲庫」設計模式開發的。在ASP.NET MVC

在我看來,它應該如此,我的應用程序有一個工作單元,它提供了對所有存儲庫的集中訪問,這些存儲庫進一步提供對實體的訪問。

假設我有一個名爲「ProductApprovalDocument」的實體,其存儲在數據庫中的屬性爲「id」,「creationDate」和「approvalDecission」。現在我希望用戶能夠訪問該實體即將描述的文檔的PDF文件。由於這些文件使用URL格式「[fileServerDirectoryPath]/[ProductApprovalDocument.id] .pdf」存儲在文件服務器上的中央目錄中,因此我不想爲數據庫上的該文件路徑另存一個屬性。我想要做的是給實體一個名爲「filepath」的額外屬性,該屬性自動構造具有給定信息的路徑並返回它。

現在的問題:

我使用所謂的FileService從應用程序的其他抽象文件訪問的接口。現在在我的情況下,我將不得不從實體模型中訪問UnitOfWork對象,以檢索當前的FileService實現並獲取預配置的文件路徑。我認爲這是完全錯誤的方式,因爲對於我來說,一個實體模型應該只能作爲數據容器使用,而不會更多或更少。

現在的問題:

我該如何處理這種情況。我不想總是通過控制器設置filepath屬性,因爲它或多或少是靜態的,因此可以通過模型以某種方式自動完成。

編輯(最終的解決方案):

感謝安德烈·洛克的答案,我獲得了另一種觀點認爲,以我的問題。

  • 我想達到的中心目標是什麼?
    • 我希望用戶能夠訪問存儲在文件服務器上的文件。
  • 我是否必須爲每個顯示的實體提供總文件路徑?
    • 不!想想MVC的原理!控制器及時處理用戶操作。您不必提供信息,直到它真的被使用。

因此解決的辦法就是要呈現的數據和往常一樣,但不是顯示一個靜態的HTML鏈接的文件,你必須包括一個ActionLink的到即時計算並自動將文件路徑控制器將用戶重定向到文件。

在視圖做到這一點:

@Html.ActionLink(Model.ID.ToString(), "ShowProductApprovalDocumentFile", "ProductApprovalDocument", new { ProductApprovalDocumentID = Model.ID }, null) 

,而不是這樣的:

<a href="@Model.FilePath">@Model.ID</a> 

而一個相應的操作添加到控制器:

public ActionResult ShowProductApprovalDocumentFile(int ProductApprovalDocumentID) 
{ 
    return Redirect(_unitOfWork.FileService.GetFilePathForProductApprovalDocument(ProductApprovalDocumentID)); 
} 

由於這一帶的傢伙給我一個答案的時候,並特別感謝安德烈誰讓我滿意的答案! :)

+0

我不確定我是否正確理解您的問題。 FileService是什麼?它是否用於從文檔ID生成文件路徑?或者它用於實際檢索文件?它與工作單位有什麼關係? – 2012-03-01 09:27:04

+0

FileService用於通過mvc應用程序進行一般文件系統訪問,例如,根據實現類型訪問,存儲和/或自動版本控制文件。換句話說,我的應用程序比我在這裏描述的要複雜得多。 是的,我也用它來生成文件路徑,授予一箇中心位置,以便爲將來的變化提供靈活性 – 2012-03-01 09:33:15

回答

1

如果我理解正確的財產,有幾個選項:

1)使文件路徑屬性中使用的服務定位找到的FileService:

public string FilePath { 
    get { 
     FileService fileService = DependencyResolver.Current.GetService<FileService>(); 
     return fileService.GetFilePathForDocument(this); 
    } 
} 

雖然我不是一個休風扇靜態服務定位器,因爲它們使測試更加困難,這可能是一個可行的選擇。爲了使它更容易測試,你可以使文件的服務定位注射:

private static readonly Func<FileService> defaultFileServiceLocator =()=>DependencyResolver.Current.GetService<FileService>(): 
private Func<FileService> fileServiceLocator = defaultFileServiceLocator; 

public Func<FileService> FileServiceLocator { 
    get { return fileServiceLocator; } 
    set { fileServiceLocator = value ?? defaultFileServiceLocator; } 
} 

然後在文件路徑

public string FilePath { 
    get { 
     FileService fileService = fileServiceLocator(); 
     return fileService.GetFilePathForDocument(this); 
    } 
} 

使用這種方式,您可以在測試過程中注入自己的文件服務定位器。

2)檢索文件路徑時顯式需要FileService。取而代之的是文件路徑屬性的你必須:

public string GetFilePath(FileService service){ 
    service.GetFilePathForDocument(this); 
} 

的問題,這當然是現在GetFilePath的調用者需要具有的FileService的。這對於控制器來說並不是什麼大問題,因爲如果你使用IoC,你可以在控制器構造函數中注入一個FileService。這種方法是更清潔的方法,因爲它不依賴於服務定位器,但正如你所看到的,對於調用者稍微不方便。

3)將FileService注入文檔類本身。

而不是使用文件服務定位器,您將構建您的ProductApprovalDocument時注入文件服務本身。使用這種方法,您可以再次使用簡單的FilePath屬性。主要的問題是這對於ORM來說通常不會太好,因爲它們通常使用默認構造函數構造對象,並且您必須以某種方式掛鉤到對象構建過程以注入依賴關係。另外,我並不是注入域對象的注入服務的忠實粉絲。

4)您從實體外部設置FilePath。正如你所說,這應該有點自動完成,因爲你不想每次都手動完成。這將需要一些圖層,所有實體需要通過該圖層來設置FilePath屬性。

5)不要使FilePath成爲ProductApprovalDocument的一個屬性。這也是一個合理的選擇。 ProductApprovalDocument不知道任何有關其FilePath的內容,爲什麼它應該是一個屬性?它是計算值的FileService。您仍然可以獲得ProductProrovalDocument的獨特視圖模型版本,其中的確具有FilePath屬性

var model = new ProductApprovalDocumentViewModel(); 
mapper.Map(realDocument, model); // map common properties with AutoMapper or so 
model.FilePath = fileService.GetFilePathForDocument(realDocument); 

但是,如果ProductApprovalDocument需要做的文件路徑什麼(爲什麼不是嗎?)這個方法不起作用了:當您創建視圖模型你會設置該屬性。

就我個人而言,如果適用,我會按照優先級順序使用解決方案5,2或1。

+0

好的答案我會試試看,好像我不會使用。 5 – 2012-03-01 10:12:58

+0

我有解決方案沒有。 6 =>根本不使用filePath,只需將一個ActionLink放置到控制器中,使用ProductApprovalDocument ID作爲值,並讓控制器使用通過工作單元實例訪問的fileService動態地創建文件路徑,這是一種合法的方式,然後重定向用戶使用創建的文件路徑 – 2012-03-01 11:01:49

0

雖然我會猶豫依靠能夠計算文件路徑,我寧願將它作爲實體的一部分存儲(如果它因某種原因需要更改),在您的情況下,如果我堅持我想按照你所說的方式去做,我想我會擴展FileService/ViewModel來擁有一個Filepath屬性,它以你所陳述的方式派生。

例如如果我想創建一個下載鏈接我的視圖模型做到這一點

public string FilePath 
{ 
    get 
    { 
     return String.Format(@"thehardcodedbit{0}.pdf",ID); 
    } 
} 

編輯:如果您已經通過EF4.x生成的實體,然後將已經產生的部分類,所以你能一直擴展它像這樣(我已經做了這樣的事情和它的作品沒關係):

說生成的實體是這樣的:

Namespace Da_Wolf.Model.Entities.File 
{ 
    public partial class UploadedFile 
    {....} 
} 

然後,你可以創建一個局部類是這樣的:

Namespace Da_Wolf.Model.Entities.File 
{ 
    public partial class UploadedFile 
    { 
    public string FilePath 
    { 
     get 
     { 
      return String.Format(@"thehardcodedbit{0}.pdf",ID); 
     } 
    } 
    } 
} 

現在,您可以隨時隨地使用所需的屬性,而無需向ViewModels添加任何內容。

+0

這正是我想要做的,但我的問題是我通過其他模型訪問該模型,例如,該文檔屬於一個「產品」實體,我有一個索引頁面列出了所有產品的一些數據,包括「ProductApprovalDocument」的ID,使用戶能夠敲擊該ID並打開文件,認爲你知道我的意思。現在,當我理解你的解決方案時,我將不得不調整所有的ViewModel以某種方式訪問​​文件,以便提供該文件路徑屬性。 進一步我想靈活的存儲路徑的未來變化 – 2012-03-01 09:43:07

+0

這是新的編輯的任何用途? – 2012-03-01 09:52:51

+0

感謝您的解釋,但我已經在使用部分類擴展我的實體的可能性,我不知道這對我有什麼幫助。因爲我的問題是我不想包含一個靜態的,但是將來可以改變的路徑。路徑存儲在我的web.config文件中,所以我也可以通過「ConfigurationManager.AppSettings [」MyStoragePath「]找回它,但我想知道這是否是一個可行的解決方案。 – 2012-03-01 10:00:37