具有不同查询选择列表的广义DTO填充方法

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (45)

由于我不太了解的原因,我选择不使用ORM框架并使用通用的ADO.NET数据访问层。我最初创建了一个数据库类,我的所有控制器都可以访问它。正如我自己所预测的那样,这个访问对象已成为一种怪异。

为了重构我的数据层,我创建了一个“数据库适配器”类作为DI注入服务,并创建了一个“服务层”来利用它。因此,每个控制器现在都有一个“域服务”,它将使用数据库适配器来查询数据库并返回通用数据表。然后,该服务将填充查询结果并将域对象返回到控制器,在那里它可以组装视图模型。

我遇到了一个问题,我似乎无法抽象设计用于映射从数据库访问层返回的DataSet的代码,因为每个查询可能会选择不同的字段。例如,一个简单的参考数据服务:

public class ReferenceDataService : IReferenceDataService
{
    private IDatabaseAdapter _dbAdapter;

    public ReferenceDataService(IDatabaseAdapter dbAdapter)
    {
        _dbAdapter = dbAdapter;
    }

    public IEnumerable<ReferenceData> GetReferenceData(string table)
    {
        List<ReferenceData> rdList = new List<ReferenceData>();

        StringBuilder sb = new StringBuilder();
        sb.Append("SELECT [CODE], [LABEL] FROM [dbo].");
        sb.Append(table);
        sb.Append(" WHERE END_DATETIME > GETDATE()");

        DataSet ds = _dbAdapter.ExecuteDataSet(sb.ToString(), null);

        foreach (DataRow row in ds.Tables[0].Rows)
        {
            rdList.Add(PopulateRecord(row));
        }

        return rdList;
    }

    private ReferenceData PopulateRecord(DataRow row)
    {
        return new ReferenceData
        {
            ReferenceId = (int)row["REFERENCE_ID"],
            Code = (string)row["CODE"],
            Label = (string)row["LABEL"],
            Description = (string)row["DESCRIPTION"],
            BeginDatetime = (DateTime)row["BEGIN_DATETIME"],
            EndDatetime = (DateTime)row["END_DATETIME"],

            UpdatedBy = (string)row["UPDATED_BY"],
            UpdatedOn = (DateTime)row["UPDATED_ON"],
            CreatedBy = (string)row["CREATED_BY"],
            CreatedOn = (DateTime)row["CREATED_ON"]
        };
    }
}

在这个例子中,我有一个从populate方法抛出的异常,因为你可以看到,我只选择这个特定方法的代码和标签。我想避免每个方法的自定义映射,但我也不想不必要地将每个表行中的所有数据都返回给控制器。我想保持populate方法的通用性,以便适当地映射针对该表的任何查询。

我意识到我基本上几乎都在使用自己的ORM,但是我想使用没有它的服务模式,因为在这一点上我太投入了。

提问于
用户回答回答于

经过一番挖掘,似乎有一个非常明显和直接的解决方案,我一直在想。DataRow实例对象能够检查其父表列是否存在。通过在其中一个检查中从表行中包装每个赋值,那么填充方法将不关心实际选择到DataTable中的内容,并且无论从查询返回的数据量如何都能够填充对象。

因此,在我的示例中,如果我想为ReferenceData保留一个通用填充方法但使用仅返回CODE和LABEL列的查询,则以下更改将使返回的业务对象的填充不可用并且没有错误:

    private ReferenceData PopulateRecord(DataRow row)
    {
        return new ReferenceData
        {
            ReferenceId = row.Table.Columns.Contains("REFERENCE_ID") ? (int)row["REFERENCE_ID"] : default(int),
            Code = row.Table.Columns.Contains("CODE") ? (string)row["CODE"] : default(string),
            Label = row.Table.Columns.Contains("LABEL") ? (string)row["LABEL"] : default(string),
            Description = row.Table.Columns.Contains("DESCRIPTION") ? (string)row["DESCRIPTION"] : default(string),
            BeginDatetime = row.Table.Columns.Contains("BEGIN_DATETIME") ? (DateTime)row["BEGIN_DATETIME"] : default(DateTime),
            EndDatetime = row.Table.Columns.Contains("END_DATETIME") ? (DateTime)row["END_DATETIME"] : default(DateTime),

            UpdatedBy = row.Table.Columns.Contains("UPDATED_BY") ? (string)row["UPDATED_BY"] : default(string),
            UpdatedOn = row.Table.Columns.Contains("UPDATED_ON") ? (DateTime)row["UPDATED_ON"] : default(DateTime),
            CreatedBy = row.Table.Columns.Contains("CREATED_BY") ? (string)row["CREATED_BY"] : default(string),
            CreatedOn = row.Table.Columns.Contains("CREATED_ON") ? (DateTime)row["CREATED_ON"] : default(DateTime)
        };
    }

这将允许我PopulateRecord在仅返回CODE和LABEL的select语句上使用(如果我为下拉列表填充SelectItemList,我想要这样做)。

我不知道这可能会或可能不会产生什么样的性能,所以这是可以考虑的事情。但这允许我寻找的灵活性。我希望这篇文章可以帮助那些可能正在寻找相同类型解决方案的人。

如果有更好的方法来解决这个问题,请告诉我。谢谢!

扫码关注云+社区

领取腾讯云代金券