繁体   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