在对表,其布局和记录建模时,如何避免代码重复,所有这些都共享相同的基本结构?

sta*_*ica 5 c# data-access-layer code-duplication separation-of-concerns

这将是一个有点抽象的问题.

我正在研究一个数据访问层框架,它需要区分表,它的抽象模式/布局和具体的表记录.我担心由于这种区别,会有很多代码重复.我可能需要一些方法来避免这种情况.

+-----------+
|    Foo    |
+-----------+
| +Id: Guid |
+-----------+
Run Code Online (Sandbox Code Playgroud)

请注意,此图可以描述以下任何一种:表模式,具体表或具体表记录,具有Id类型的字段Guid.

  • 架构中已知的所有内容都是字段的名称和类型.
  • 在具体(打开)表中,字段的"列索引"是另外已知的.
  • 有了记录,所有这些都是已知的,而且该字段具有特定的价值.

把它翻译成代码,我会得到很多类似的类型(成对的三种).我将使用接口来保持示例简短; 我要展示的是类型的相似性:

// these interfaces only need to be implemented once:

interface ISchemaField<T>  {  string Name  { get; }       }


interface ITableField<T>   {  string Name  { get; }        
                              int    Index { get; }       }

interface IRecordField<T>  {  string Name  { get; }        
                              int    Index { get; }       
                              T      Value { get; set; }  }
Run Code Online (Sandbox Code Playgroud)
// these three interfaces are an example for one entity; there would be
// three additional types for each additional entity.

interface IFooSchema
{
    ISchemaField<Guid> Id { get; }
    IFooTable Open(IDbConnection dbConnection, string tableName);
}

interface IFooTable
{
    ITableField<Guid> Id { get; }
    ICollection<IFooRecord> ExecuteSomeQuery();
}

interface IFooRecord
{
    IRecordField<Guid> Id { get; }
}
Run Code Online (Sandbox Code Playgroud)

现在我想避免为具体数据模型中的每个实体编写三个非常类似的实现.有哪些方法可以减少代码重复?

  • 我已经想过代码生成(例如T4),这将是一个很好的解决方案,但我更喜欢"手动"编码的解决方案(如果有的话),代码行数更少,代码更易读.

  • 我已经考虑过为每个实体创建一个类,它同时实现了模式,表和记录接口......但是这感觉很混乱,就像违反了Separation of Concerns.

Die*_*ego 1

恕我直言,我认为您对表结构的抽象有点太过了。过度使用接口会使代码难以阅读。我觉得很烦人,例如,你不能按 F12 查看对象的实现,因为它是接口类型。

我使用了多年并且非常容易维护的一个经过验证的模型是使所有类名称与表名称相同,然后使字段名称与列名称匹配。然后,您只需在编辑器中使用搜索和替换即可轻松生成方法,代码更改也是如此。这样您就不需要将列名和列索引保留在内存中。您只需在数据访问层中对它们进行硬编码(硬编码并不总是坏事!)。例如:

this.Price = reader["Price"] as decimal?;
Run Code Online (Sandbox Code Playgroud)

这种方法的性能非常好,并且代码非常易于维护!

无论您采用哪种方法,关键是如何保留从表列到类属性的映射。我建议对它们进行硬编码并使用简单的命名约定(列名称 = 属性名称)。这种方法要求您在添加或更改列时重新编译,但我认为这些更改发生的频率不足以证明将列名放在变量中或从单独的文件中读取它们是合理的。这样做可以避免重新编译,但会使代码不太容易理解。我认为这不值得。