【问题标题】:Using dapper with JOIN在 JOIN 中使用 dapper
【发布时间】:2019-08-10 08:15:54
【问题描述】:

我有一个包含多个连接的查询,例如:

var sqlFindByProviderNameAndProviderSubjectId = $@"
     SELECT u.*, la.*, p.*, cp.*, scr.*, lm.*, wm.*
     FROM [user].[User] u
     LEFT JOIN [user].[LinkedAccount] la ON u.Id = la.UserId
     LEFT JOIN [user].[PatientProfile] p ON u.Id = p.UserId
     LEFT JOIN [user].[CareProviderProfile] cp ON u.Id = cp.UserId                
     LEFT JOIN [user].[Screening] scr ON u.Id = scr.UserId
     LEFT JOIN [user].[LengthMeasurement] lm ON scr.Id = lm.ScreeningId
     LEFT JOIN [user].[WeightMeasurement] wm ON scr.Id = wm.ScreeningId                 
                WHERE u.Id = (
                    SELECT UserId
                    FROM [user].[LinkedAccount] la
                    WHERE la.ProviderName = @ProviderName AND la.ProviderSubjectId = @ProviderSubjectId)";

我使用 dapper 将表格非实体化为强类型实体,例如:

await UnitOfWork.Connection.QueryAsync<User, LinkedAccount, PatientProfile, CareProviderProfile, Screening, LengthMeasurement, WeightMeasurement, User>(query,
    (u, la, p, cp, scr, lm, wm) =>
    {
        // mapping code here
    }

这很好用。

但是,我必须向查询中添加一个额外的 JOIN,但不幸的是 QueryAsync 最多需要 7 个参数/类型,而且我还有更多。

还有其他方法可以将多个表从 JOIN 映射到实体吗?

【问题讨论】:

  • 除非您执行以下方法,否则您必须单独调用以构建该实体结构,然后在代码中关联到父实体。多重映射只嵌套到七个。

标签: c# sql join asp.net-core dapper


【解决方案1】:

所以这就是我最终要做的。

我的主要查询只检索用户、关联帐户和个人资料:

var sqlFindByProviderNameAndProviderSubjectId = $@"
            SELECT u.*, la.*, p.*, cp.*
            FROM [user].[User] u
            LEFT JOIN [user].[LinkedAccount] la ON u.Id = la.UserId
            LEFT JOIN [user].[PatientProfile] p ON u.Id = p.UserId
            LEFT JOIN [user].[CareProviderProfile] cp ON u.Id = cp.UserId                
            WHERE u.Id = (
                SELECT UserId
                FROM [user].[LinkedAccount] la
                WHERE la.ProviderName = @ProviderName AND la.ProviderSubjectId = @ProviderSubjectId)";

应用层可以指定一个布尔值IncludeScreening,如果为真,我还做第二次调用来获取筛选信息:

var sqlFindScreeningForUser = $@"
                SELECT scr.*, lm.*, wm.*, n.*
                FROM [user].[Screening] scr                
                LEFT JOIN [user].[LengthMeasurement] lm ON scr.Id = lm.ScreeningId
                LEFT JOIN [user].[WeightMeasurement] wm ON scr.Id = wm.ScreeningId
                LEFT JOIN [user].[Note] n ON scr.Id = n.ScreeningId
                WHERE scr.UserId = @UserId";

...然后将生成的Screening 设置在用户身上。

【讨论】:

    【解决方案2】:

    Dapper 不关心你的连接,Dapper 关心的是表格结构。框架默认使用 id 列,或自定义SplitOn 将表格结构解析为对象。所以表格结构如下:

    Tabular:
    Id | A | Id | B | Id | C | Id | D | Id | E | Id | F | Id | G | Id | H
    

    您告诉 Dapper 存在八个实体,Dapper 通过 id 列执行此操作。现在,如果您有一个实体,但不需要以这种方式抽象,例如 A、B 和 C 应该在一个实体中,那么您可以告诉 Dapper 不要通过生成以下内容为它们创建单独的实体结构。

    Tabular:
    Id | A | B | C | Id | D | Id | E | Id | F | Id | G | Id | H
    

    我的意思是一个实体不应该代表一个表格,而是一个代表你意图的对象。例如,用户可能有地址信息,但在数据库中它们可能是单独的表,但在您的应用程序中它们可能是一个对象。

    根据数据表,我假设您可以在不失去业务意图的情况下合并一对。哪个基于拆分将解决您的问题,否则我不确定您将如何超过 Dapper 内置的七个拆分功能。

    【讨论】:

    • 感谢您的澄清。但是这些表对应于单独的实体。我想我将不得不将它分成两个查询......
    猜你喜欢
    • 1970-01-01
    • 2011-09-06
    • 2013-09-17
    • 2013-03-07
    • 2015-02-28
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    相关资源
    最近更新 更多