简体   繁体   中英

Using dapper with JOIN

I have a query with a number of joins like:

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)";

I use dapper to dematerialize the tables into strongly typed entities like:

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

This works fine.

However, I have to add one additional JOIN to the query, but unfortunately the QueryAsync<> takes maximum 7 parameters/types, and I have more.

Is there another way to map multiple tables from a JOIN into entities?

Dapper does not care about your joins, what Dapper does care about is the tabular structure. The framework uses an id column by default, or a custom SplitOn to parse the tabular structure into an object. So a tabular structure in the following manner:

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

You are telling Dapper that eight entities exists, Dapper does this by the id column. Now, if you have an entity but it does not require to be abstracted in this manner, for instance A, B, and C should be in a single entity then you can tell Dapper to not create a separate entity for them by producing the following structure.

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

The point I am making is an entity should not represent a table, but an object that represents your intent. For instance a user may have address information, but in a database they'll likely be separate tables but in your application they may be one object.

Based on the data tables I assume you can merge a couple without loosing business intent. Which based on the split would resolve your issue, otherwise I am not sure how you would exceed the seven split functionality built into Dapper.

So this is what I ended up doing.

My main query only retrieves user, linked accounts, and profile:

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)";

The application layer can specify a boolean IncludeScreening , and if true, I also do a second call to get the screening information:

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";

...and the resulting Screening is then set on the user.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM