【问题标题】:Extending Query<T, ..> to more than 7 types将 Query<T, ..> 扩展到超过 7 种类型
【发布时间】:2014-11-03 20:59:34
【问题描述】:

我正在使用 Dapper 来获取结果列表。我有很多只包含 ID 和名称的“价值”表。

我有这个 SQL;

SELECT 
    MedicationScheduleItem.*,
    MedicationSchedule.*,
    Patient.*,
    Medication.*,
    MedicationBrand.*,
    MedicationScheduleItemRepeat.*,
    MedicationType.*,
    Measure.*

FROM MedicationScheduleItem
JOIN MedicationSchedule ON (MedicationSchedule.Id = MedicationScheduleItem.MedicationScheduleId)
JOIN Patient ON (Patient.Id = MedicationSchedule.PatientId)
JOIN Medication ON (Medication.Id = MedicationScheduleItem.MedicationId)
JOIN MedicationBrand ON (MedicationBrand.Id = Medication.MedicationBrandId)
JOIN MedicationType ON (MedicationType.Id = Medication.MedicationTypeId)
JOIN Measure ON (Measure.Id = Medication.MeasureId)
LEFT JOIN MedicationScheduleItemRepeat ON (MedicationScheduleItemRepeat.MedicationScheduleItemId = MedicationScheduleItem.Id)

我正在尝试将该 SQL 映射到这样的模型;

using Dapper;

//... 

private readonly IDbConnection _connection;

//... 

private IEnumerable<MedicationScheduleResultModel> QueryMedicationScheduleResultModels(string sql, object parameters = null)
{
    var results = new Dictionary<int, MedicationScheduleResultModel>();

    _connection.Query<MedicationScheduleItem, MedicationSchedule, Patient, Medication, MedicationBrand, MedicationScheduleItemRepeat, MedicationType, Measure, MedicationScheduleResultModel>(sql,
                (medicationScheduleItem, medicationSchedule, patient, medication, medicationBrand, medicationScheduleItemRepeat, medicationType, measure) =>
                {
                    MedicationScheduleResultModel viewModel;
                    if (!results.TryGetValue(medicationSchedule.Id, out viewModel))
                    {
                        results.Add(medicationSchedule.Id, new MedicationScheduleResultModel
                        {
                            Id = medicationSchedule.Id,
                            Patient = patient,
                            TimeCreated = medicationSchedule.TimeCreated,
                            StartDate = medicationSchedule.StartDate,
                            Schedules = new List<MedicationScheduleItemResultModel>()
                            {
                                BuildMedicationScheduleItemResultModel(medicationScheduleItem,
                                    medicationScheduleItemRepeat, medication, medicationBrand, medicationType, measure)
                            }
                        });
                    }
                    else
                    {
                        viewModel.Schedules.Add(BuildMedicationScheduleItemResultModel(medicationScheduleItem,
                            medicationScheduleItemRepeat, medication, medicationBrand));
                    }

                    return viewModel;
                }, parameters, splitOn: "Id, MedicationScheduleItemId");

    return results.Values;
}

private static MedicationScheduleItemResultModel BuildMedicationScheduleItemResultModel(MedicationScheduleItem medicationScheduleItem, MedicationScheduleItemRepeat medicationScheduleItemRepeat, Medication medication, MedicationBrand medicationBrand, MedicationType medicationType, Measure measure)
{
    return new MedicationScheduleItemResultModel()
    {
        Id = medicationScheduleItem.Id,
        ExecuteTime = medicationScheduleItem.ExecuteTime,
        RepeatTimeSpan = medicationScheduleItemRepeat != null
            ? (TimeSpan?)TimeSpan.FromTicks(medicationScheduleItemRepeat.RepeatTimeSpan)
            : null,
        Medication = new MedicationResultModel()
        {
            Id = medication.Id,
            Name = medication.Name,
            Brand = new MedicationBrand()
            {
                Id = medicationBrand.Id,
                Name = medicationBrand.Name
            },
            Measure = measure.Name,
            Type = medicationType.Name,
            Weight = medication.Weight
        }
    };
}

但是_connection.Query&lt;T, ..&gt; 失败了,因为有很多泛型类型。

有没有办法让它工作,还是我做错了?

【问题讨论】:

  • 什么是_connection
  • 我更新了问题,是IDbConnection
  • 你能把BuildMedicationScheduleItemResultModel的代码贴出来吗?如果您在其中所做的只是构造MedicationScheduleItemResultModel 并从输入对象分配属性,那么您应该修改您的SQL 查询以返回适当的列并让Dapper 直接为您创建MedicationScheduleItemResultModel
  • @ErenErsönmez 我已经更新了问题,我所做的只是将字段映射到模型。

标签: c# sql generics mapping dapper


【解决方案1】:

您可以尝试直接映射到您感兴趣的最终类型,而不是将您的 SQL 结果映射到所有这些类型并仅在初始化另一种类型时使用它们。

所以不要这样:

_connection.Query<MedicationScheduleItem, MedicationSchedule, Patient, 
    Medication, MedicationBrand, MedicationScheduleItemRepeat, MedicationType,
    Measure, MedicationScheduleResultModel>(...

这可能足以构建您需要的对象图:

_connection.Query<MedicationScheduleResultModel, Patient, 
    MedicationScheduleItemResultModel, MedicationResultModel, MedicationBrand>(...

当然,这需要修改您的SELECT 以返回适当的字段。比如……

SELECT
    -- columns that directly map to MedicationScheduleResultModel properties
    MedicationSchedule.id,
    MedicationSchedule.time_created TimeCreated, 
    MedicationSchedule.start_date StartDate,

    -- columns that directly map to Patient properties
    -- (to be used as MedicationScheduleResultModel.Patient)
    Patient.id, 
    Patient.name,

    -- columns that directly map to MedicationScheduleItemResultModel properties
    MedicationScheduleItem.id,
    MedicationScheduleItem.execute_time ExecuteTime,
    MedicationScheduleItemRepeat.repeat_time RepeatTime,

    -- columns that directly map to MedicationResultModel properties
    Medication.id,
    Medication.name,
    Measure.name,
    MedicationType.name,
    Medication.weight,

    -- columns that directly map to MedicationBrand properties
    MedicationBrand.id, 
    MedicationBrand.name
...

希望你能明白。

您甚至可以进一步展平,例如,MedicationResultModel,以便它不包含复杂的MedicationBrand 属性,而是包含MedicationBrandIdMedicationBrandName 属性。但这取决于这是否适合您的其余设计。

【讨论】:

  • 好的,那么 dapper 会知道顺序然后正确映射吗?我应该将 MedicationType.Name 别名为 Type 吗?否则我将有 2 个名称为“名称”
  • @TryingToImprove 是的,当 dapper 看到一个名为“id”的新列时,它会知道新类型何时开始。如果您想从不同的列名开始,您需要使用Query 方法的SplitOn 参数显式声明该列。不,名为Name 的两列应该不成问题。
  • @TryingToImprove 实际上,再次查看简洁的代码,您的列名需要匹配属性名(尽管它可能不区分大小写)。所以它会成功地将id 列映射到Id,但在start_date 的情况下,它不会映射到StartDate,所以你需要提供一个列别名(我已经编辑了上面的示例)。跨度>
  • 谢谢它的工作,-我的数据库列与 C# 对象同名,可以这样做:pastebin.com/kipYdqiy
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-05
  • 1970-01-01
相关资源
最近更新 更多