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