22using System . Collections . Generic ;
33using System . Data ;
44using System . Linq ;
5+ using System . Text ;
56using System . Threading . Tasks ;
67using Dapper ;
78
@@ -44,8 +45,13 @@ internal static string BuildProjectById(ISqlBuilder sqlBuilder, Type type, objec
4445 var cacheKey = new QueryCacheKey ( QueryCacheType . Project , sqlBuilder , type ) ;
4546 if ( ! QueryCache . TryGetValue ( cacheKey , out var sql ) )
4647 {
47- var keyProperty = Resolvers . KeyProperties ( type ) . Single ( ) . Property ;
48- var keyColumnName = Resolvers . Column ( keyProperty , sqlBuilder ) ;
48+ var keyProperties = Resolvers . KeyProperties ( type ) ;
49+ if ( keyProperties . Length > 1 )
50+ {
51+ throw new InvalidOperationException ( $ "Entity { type . Name } contains more than one key property." +
52+ "Use the Project<T> overload which supports passing multiple IDs." ) ;
53+ }
54+ var keyColumnName = Resolvers . Column ( keyProperties [ 0 ] . Property , sqlBuilder ) ;
4955
5056 sql = BuildProjectAllQuery ( sqlBuilder , type ) ;
5157 sql += $ " where { keyColumnName } = @Id";
@@ -58,6 +64,104 @@ internal static string BuildProjectById(ISqlBuilder sqlBuilder, Type type, objec
5864 return sql ;
5965 }
6066
67+ /// <summary>
68+ /// Retrieves the entity of type <typeparamref name="TEntity"/> with the specified id.
69+ /// </summary>
70+ /// <typeparam name="TEntity">The type of the entity.</typeparam>
71+ /// <param name="connection">The connection to the database. This can either be open or closed.</param>
72+ /// <param name="ids">The id of the entity in the database.</param>
73+ /// <returns>The entity with the corresponding id.</returns>
74+ public static TEntity ? Project < TEntity > ( this IDbConnection connection , params object [ ] ids ) where TEntity : class
75+ => Project < TEntity > ( connection , ids , transaction : null ) ;
76+
77+ /// <summary>
78+ /// Retrieves the entity of type <typeparamref name="TEntity"/> with the specified id.
79+ /// </summary>
80+ /// <typeparam name="TEntity">The type of the entity.</typeparam>
81+ /// <param name="connection">The connection to the database. This can either be open or closed.</param>
82+ /// <param name="ids">The id of the entity in the database.</param>
83+ /// <param name="transaction">Optional transaction for the command.</param>
84+ /// <returns>The entity with the corresponding id.</returns>
85+ public static TEntity ? Project < TEntity > ( this IDbConnection connection , object [ ] ids , IDbTransaction ? transaction = null ) where TEntity : class
86+ {
87+ if ( ids . Length == 1 )
88+ {
89+ return Project < TEntity > ( connection , ids [ 0 ] , transaction ) ;
90+ }
91+
92+ var sql = BuildProjectByIds ( GetSqlBuilder ( connection ) , typeof ( TEntity ) , ids , out var parameters ) ;
93+ LogQuery < TEntity > ( sql ) ;
94+ return connection . QueryFirstOrDefault < TEntity > ( sql , parameters , transaction ) ;
95+ }
96+
97+ /// <summary>
98+ /// Retrieves the entity of type <typeparamref name="TEntity"/> with the specified id.
99+ /// </summary>
100+ /// <typeparam name="TEntity">The type of the entity.</typeparam>
101+ /// <param name="connection">The connection to the database. This can either be open or closed.</param>
102+ /// <param name="ids">The id of the entity in the database.</param>
103+ /// <returns>The entity with the corresponding id.</returns>
104+ public static Task < TEntity ? > ProjectAsync < TEntity > ( this IDbConnection connection , params object [ ] ids ) where TEntity : class
105+ => ProjectAsync < TEntity > ( connection , ids , transaction : null ) ;
106+
107+ /// <summary>
108+ /// Retrieves the entity of type <typeparamref name="TEntity"/> with the specified id.
109+ /// </summary>
110+ /// <typeparam name="TEntity">The type of the entity.</typeparam>
111+ /// <param name="connection">The connection to the database. This can either be open or closed.</param>
112+ /// <param name="ids">The id of the entity in the database.</param>
113+ /// <param name="transaction">Optional transaction for the command.</param>
114+ /// <returns>The entity with the corresponding id.</returns>
115+ public static async Task < TEntity ? > ProjectAsync < TEntity > ( this IDbConnection connection , object [ ] ids , IDbTransaction ? transaction = null ) where TEntity : class
116+ {
117+ if ( ids . Length == 1 )
118+ {
119+ return await ProjectAsync < TEntity > ( connection , ids [ 0 ] , transaction ) ;
120+ }
121+
122+ var sql = BuildProjectByIds ( GetSqlBuilder ( connection ) , typeof ( TEntity ) , ids , out var parameters ) ;
123+ LogQuery < TEntity > ( sql ) ;
124+ return await connection . QueryFirstOrDefaultAsync < TEntity > ( sql , parameters , transaction ) ;
125+ }
126+
127+ internal static string BuildProjectByIds ( ISqlBuilder sqlBuilder , Type type , object [ ] ids , out DynamicParameters parameters )
128+ {
129+ var cacheKey = new QueryCacheKey ( QueryCacheType . ProjectByMultipleIds , sqlBuilder , type ) ;
130+ if ( ! QueryCache . TryGetValue ( cacheKey , out var sql ) )
131+ {
132+ var keyProperties = Resolvers . KeyProperties ( type ) ;
133+ var keyColumnNames = keyProperties . Select ( p => Resolvers . Column ( p . Property , sqlBuilder ) ) . ToArray ( ) ;
134+ if ( keyColumnNames . Length != ids . Length )
135+ {
136+ throw new InvalidOperationException ( $ "Number of key columns ({ keyColumnNames . Length } ) of type { type . Name } does not match with the number of specified IDs ({ ids . Length } ).") ;
137+ }
138+
139+ var sb = new StringBuilder ( BuildProjectAllQuery ( sqlBuilder , type ) ) . Append ( " where" ) ;
140+ var i = 0 ;
141+ foreach ( var keyColumnName in keyColumnNames )
142+ {
143+ if ( i != 0 )
144+ {
145+ sb . Append ( " and" ) ;
146+ }
147+
148+ sb . Append ( ' ' ) . Append ( keyColumnName ) . Append ( $ " = { sqlBuilder . PrefixParameter ( "Id" ) } ") . Append ( i ) ;
149+ i ++ ;
150+ }
151+
152+ sql = sb . ToString ( ) ;
153+ QueryCache . TryAdd ( cacheKey , sql ) ;
154+ }
155+
156+ parameters = new DynamicParameters ( ) ;
157+ for ( var i = 0 ; i < ids . Length ; i ++ )
158+ {
159+ parameters . Add ( "Id" + i , ids [ i ] ) ;
160+ }
161+
162+ return sql ;
163+ }
164+
61165 /// <summary>
62166 /// Retrieves all the entities of type <typeparamref name="TEntity"/>.
63167 /// </summary>
0 commit comments