簡體   English   中英

實體框架向屬性添加功能

[英]Entity Framework adding functionality to Properties

在一個舊的WPF項目中,我有一個帶有Properties的類,如下所示:

    private string _name = "";
    public string Name
    {
        get { return _name; }
        set
        {
            string cleanName = clsStringManip.CleanText(value, true);
            if (cleanName != _name)
            {
                _name = cleanName;
            }
        }
    }

每當名稱更改時,我都確保該值是“ cleaned”的。 將其放在屬性中可確保我永遠不會忘記在對象上設置屬性之前清除字符串。

現在,我使用MVC5和EntityFramework6.1和DatabaseFirst重新創建此系統。

因此,所有屬性都是由EF自動生成的。 然后如何在不編輯自動生成代碼的情況下將等效的CleanText函數添加到屬性中? -下次更改數據庫並重新同步時,我將丟失這些更改。

我可以通過Google找到的所有方法都是通過MetadataType和局部類添加數據注釋的方法,但這無法回答我的問題。

我試圖將以上代碼添加到部分類中,但出現錯誤:

XXX類型已經包含名稱的定義

我能想到的唯一方法是創建一堆SetProperty()函數,但這很臟,您無法確保其他開發人員(或我自己)會記得使用它們。

免責聲明:我還沒有使用過EF 6。

讓我分兩部分回答。 首先,我將告訴您如何執行此操作。 然后,我將告訴您為什么我不認為您應該這樣做。 :-)

怎么樣:

如發現的那樣,您無法創建另一個Name屬性。 您需要修改EF生成代碼的方式,以便為您提供插入新代碼的位置。 根據您使用EF的方式,它通常會生成Validate()方法調用或OnPropertyChanged()調用。 您可能可以在這些方法中執行所需的操作。

如果您不能在Validate()OnPropertyChanged()執行此操作,則可以更改T4模板以生成如下內容:

private string _name = "";
public string Name
{
    get { return _name; }
    set
    {
        string cleanName = value;
        Cleanup_Name(ref cleanName);
        if (cleanName != _name)
        {
            _name = cleanName;
        }
    }
}

private partial void Cleanup_Name(ref string);

這為您提供了部分方法 ,然后您可以視需要實現該方法 因此,對於您要自定義的任何屬性,現在可以將另一個文件添加到您的項目中,以執行以下操作:

public partial class MyEntity {
   void Cleanup_Name(ref string name)
   {
      // Put your logic in here to fixup the name
   }
}

如果您不編寫上述代碼塊,那么partial方法就是一個空操作。 (部分方法必須返回void,因此要使用ref參數)。

為什么不?

這種方法的優點是對開發人員完全透明。 該屬性只是神奇地更改。 但是有幾個缺點:

某些控件希望,如果他們調用name =“ 123”,則如果將其取回,則為“ 123”,並且如果發生這種情況將失敗。 值正在更改,但不會觸發PropertyChanged事件。 如果您確實觸發了PropertyChanged ,則有時它們會將值改回來。 這可能會導致無限循環。

沒有反饋給用戶。 他們輸入了一件事,看起來不錯,但現在卻說了另一番話。 有些控件可能會顯示更改,而其他控件則不會。

沒有反饋給開發人員。 監視窗口似乎將更改值。 而且在哪里可以看到驗證規則並不明顯。

實體框架本身從數據庫加載數據時會使用這些方法。 因此,如果數據庫中已經包含與清除規則不匹配的值,則從數據庫加載時將清除它們。 這可能導致LINQ查詢行為異常,具體取決於在SQL Server上運行的是哪種邏輯以及在C#代碼中運行的是哪種邏輯。 SQL代碼將看到一個值,C#將看到另一個值。

在這種情況下,您可能還想研究實體框架的更改跟蹤。 如果屬性集在從數據庫加載值時進行清理,那么它是否認為對實體的更改? .Save()調用會把它寫回到數據庫嗎? 這會導致原本不打算更改數據庫的代碼突然這樣做嗎?

備選

我不建議這樣做,而是建議創建一個Validate()方法,該方法查看每個屬性並返回指示錯誤的錯誤。 您甚至可以創建一個Cleanup()方法來修復錯誤的內容。 這意味着清除不再透明,因此開發人員必須顯式調用它們。 但這是一件好事:代碼不會在沒有意識到的情況下更改值。 編寫業務邏輯或UI的人知道值將在什么時候更改,並可以獲得原因列表。

實現此目的的唯一方法是創建一個在應用程序中實際使用的新屬性。 也許您可以在設計器中隱藏原始屬性。 您使用的實際屬性可能如下所示:

public string ExternalName
{
    get { return Name; }
    set
    {
        string cleanName = clsStringManip.CleanText(value, true);
        if (cleanName != Name)
        {
            Name = cleanName;
        }
    }
}

或者,可以使用POCO類:

  1. partial添加到生成的類。
  2. 將生成的類中Name的范圍從public更改為internal
  3. 在同一程序集中添加以下內容:

public partial class classname
{
    [NotMapped]
    public string CleanName
    {
        get { return Name; }
        set
        {
            var cleanName = clsStringManip.CleanText(value, true);
            if (cleanName != Name)
                Name = cleanName;
        }
    }
}
  1. 注意:每次重新生成POCO時,您都必須記住要執行第1-2步。我會認真考慮將Code First轉換為現有數據庫

編輯

可選:

  1. 在生成的classname Name中將Name重命名為InternalName [Column("Name")]裝飾它。
  2. 在您控制下的partial class ,將CleanName重命名為Name
  3. 4中的警告變成“每次重新生成POCO時都要記住執行步驟1、2 和5 ”。

這種方法的另一個好處是不必修改任何客戶端代碼(即,使用Name仍然是Name )。 而且我仍然會強烈考慮將Code First應用於現有數據庫

暫無
暫無

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

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