簡體   English   中英

如何使用反射或泛型來標准化泛型Entity Framework C#代碼?

[英]How to standardize generic Entity Framework C# code using reflection or generics?

我有三個數據庫表,它們代表普通名稱字符串的比較分數。 它們被分成單獨的表以加快掃描時間。 它們全部具有相同的四列基本結構:一個ID,兩個字符串和代表字符串不同程度的分數。

可通過實體框架訪問數據庫。 在實現代碼中,這使我擁有三個幾乎相同的函數,每個對象類型一個:

    private bool CheckSurnameJw(string string1, string string2, double threshold)
    {
        JwDistanceSurname jw = _rep.GetJwDistanceSurname(string1, string2);

        if (jw == null)
        {
            double dist = JaroWinklerProximity(string1, string2);
            JwDistanceSurname newJw = new JwDistanceSurname { Surname1 = string1, Surname2 = string2, JwScore = dist };
            _rep.Update(newJw);
            _rep.SaveChanges();

            return dist >= surnameProximityThreshold;
        }
        else
        {
            return jw.JwScore >= threshold;
        }
    }

看着這一點,雖然我可以稍稍捏捏和折彎,但看不到任何清晰的區域,可以通過將代碼植入另一個功能來合理地改善該功能。 但這使我煩惱,不得不重新執行同一邏輯塊三次,以處理三種不同的身份類型。

我將所有三個類包裝在一個指定四列的接口中,以查看這是否有助於我進行整理。 但事實並非如此:我不能使用通用的“ get”函數,因為每個函數都在查詢不同的表,同樣,當我創建該類的新實例時,需要給它提供適當的類型。

有沒有一種方法可以使用反射/泛型來改善這一點?

如果您的四個列都具有相同的columnName,那么我肯定會使用Table Per Type或某種Composition進行繼承

但是,如果這四列沒有共同的含義,我將使用一個接口。

每個類型的表方法

如果四列通常表示同一事物,並且您會認為表是這種常見事物的特殊種類,請使用此方法:

abstract class Common
{
    public string String1 {get; set;}
    public string string2 {get; set;}
    public double Threshold {get; set;} 
}

class Table1 : Common
{
     public int Id {get; set;}
     ...
}

class Table2 : Common
{
     public int Id {get; set;}
     ...
}

您的DbContext將像:

class MyDbContext : DbContext
{
    public DbSet<Table1> Table1s {get; set;}
    public DbSet<Table2> Table2s {get; set;}

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Table1>().ToTable("Table1s");
        modelBuilder.Entity<Table2>().ToTable("Table2s");
    }
}

這足以使實體框架設計兩個表,其中每個表具有四個公共列。

DbSet表示數據庫中的表。 數據庫不知道CheckSurName 因此,我選擇不讓Common類知道如何CheckSurName 我改為創建Common的擴展功能。

參見神秘的擴展方法

static class CommonExtensions
{
    public static bool CheckSurName(this Common common)
    {
        JwDistanceSurname jw = _rep.GetJwDistanceSurname(common.String1, common.String2);
        ...
    }
}

用法:

IEnumerable<Table1> myTableCollection = myDbContext.Table1s
    .Where(table => table...)
foreach (Table1 table1 in myTableCollection)
{
     bool surNameOk = table1.CheckSurName();
     Process(surNameOk);
}

合成方法

作為大多數開發人員,我更喜歡組合而不是繼承。 方法將類似,但是使用繼承組合代替

class Common ...

class Table1
{
    public int Id {get; set;}
    public Common Common {get; set;}
}

等等。這還將導致每種類型一個表,每個表包含所有Common屬性。 擴展功能將類似。 唯一的區別是您不對檢索表上的姓氏進行檢查,而是對檢索表的公用名進行檢查:

IEnumerable<Table1> retrievedTables = ...
foreach (Table1 table in retrievedTables)
{
    bool SurnameOk = table1.Common.CheckSurName();
    ...
}

如果Common代表某個人,而您的表代表具有一個人的項目,例如帶有老師的SchoolClass和帶有MasterMaster的學校,那么我肯定會采用這種方法。 畢竟學校不是一個人。

接口方式

您將列描述為僅是常見的類型,而不是名稱或含義。 您只有兩個字符串和一個雙精度字符串(還有一個ID,在您的CheckSurName中丟失了一個ID),唯一的共同點是它們是兩個字符串和一個雙精度整數。 在那種情況下,我會選擇一個接口。

具有CheckSurName所需屬性的對象將實現ISurNameCheckable

interface ISurnameCheckable
{
    public string String1 {get;}
    public string String2 {get;}
    public double Threshold {get;}
}

class Table1 : ISurnameCheckable
{
    public int Id {get; set;}
    public string Street {get; set;}
    public string City {get; set}

    // implementation of ISurnameCheckable
    public string String1 {get{return this.Street;}}
    public string String2 {get{return this.City;}}
    ...
}

擴展功能幾乎相同:

public static bool CheckSurName(this ISurnameCheckable surnameCheckable)
{
    JwDistanceSurname jw = _rep.GetJwDistanceSurname(
       surnameCheckable.String1, surnameCheckable.String2);
    ...
}

暫無
暫無

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

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