首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >具有不同查询选择列表的通用DTO填充方法

具有不同查询选择列表的通用DTO填充方法
EN

Stack Overflow用户
提问于 2019-05-05 11:50:24
回答 1查看 52关注 0票数 0

由于我不太理解的原因,我选择不使用ORM Framework,而是使用通用的ADO.NET数据访问层。我最初创建了一个数据库类,我的所有控制器都可以访问它。除了我之外,任何人都可能预测到,这个access对象已经变成了一个庞然大物。

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

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

代码语言:javascript
复制
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方法抛出了一个异常,因为正如您所看到的,我只为这个特定的方法选择了代码和标签。我希望避免每个方法都有一个自定义映射,但我也不希望不必要地将每个表行中的所有数据返回给控制器。我希望使填充方法保持泛型,以便对该表的任何查询都将被适当地映射。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-16 06:04:09

经过一番钻研,似乎有一个我一直遗漏的非常明显和直接的解决方案。DataRow实例对象能够检查其父表列是否存在。通过将表行中的每个赋值包装在其中一个检查中,population方法将不关心在DataTable中实际选择了什么,并且将能够填充对象,而不管从查询返回的数据量是多少。

因此,在我的示例中,如果我希望保留ReferenceData的通用填充方法,但使用仅返回代码和标签列的查询,则以下更改将使返回的业务对象的填充保持不可知和无错误:

代码语言:javascript
复制
    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)
        };
    }

这将允许我在只返回代码和标签的select语句上使用PopulateRecord (例如,当我填充下拉列表的SelectItemList时,我会这样做)。

我不知道这可能会或不会对性能造成什么样的影响,所以这是一个可能需要考虑的问题。但这允许我所寻找的灵活性。我希望这篇文章能帮助其他可能正在寻找同样类型的解决方案的人。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55988676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档