[英]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.