1

I have created this generic method:

/// <summary> /// Executes a list of items /// </summary> /// <param name="procedureName">The name of the procedure</param> /// <param name="parameters">List of oracle parameters</param> /// <param name="limit">The limit of the results to return</param> /// <param name="mapper">The oracle mapper method</param> /// <returns></returns> protected async Task<IEnumerable<T>> ListAsync<T>(string procedureName, IList<OracleParameter> parameters, int limit, Func<IDataReader, T> mapper) { // Create our list var models = new List<T>(); var counter = 0; // Get our reader and return our model using (var reader = await _oracleUnitOfWork.ExecuteReaderAsync(procedureName, parameters)) { // While we have rows and our counter while (reader.Read() && ((counter < limit || limit == 0) || limit == 0)) { // If we have a limit, increase our counter (this is first to stop 0 based index messing the amount of objects to return) if (limit > 0) counter++; // Get our item from the database models.Add(mapper(reader)); } } // Return our list return models; } 

Which I can invoke like this:

return await ListAsync("IBPA_MANFCOMPLAINT.complaintSearch", parameters, yield, OracleMapper.Complaint.Map); 

But I want to extend this a little. The Mapper just uses the IDataReader to assign the column values to the model properties. For stock instead of using this:

return await ListAsync("ibpa_stock.readRelatedLotstoLot", parameters, 0, OracleMapper.Stock.Map); 

I want to do a get request, a bit like this:

return await ListAsync("ibpa_stock.readRelatedLotstoLot", parameters, 0, async (reader) => await GetAsync(reader["lotno"].ToString())); 

What can I do to keep things DRY, but at the same time to allow that invocation?

5
  • Is the problem that you sometimes have an async method and sometimes not? And the type Func<IDataReader, T> can't accomodate both? Commented Jan 11, 2018 at 15:38
  • Note that I'd strongly suggest you not have a method like this in the first place. Rather than having a single method that executes a procedure, takes the first N values of the result, and then maps each value to something else, taking in all of the information to do all of those things, you should instead have a method that gets the results of a procedure. If someone wants the first N items, they can call a method to take the first N items (Take). If they want to map the items into something else, they can call a method to do that (Select). You're not getting anything out doing this. Commented Jan 11, 2018 at 16:03
  • Yeah I know this :D but unfortunately I have no control over the sprocs Commented Jan 11, 2018 at 16:42
  • @r3plica You don't need to change anything about the stored procedures to make such a change, you just need to remove this unhelpful method and call the method that does each thing that you want when you want to do a thing, rather than trying to do them all at once, given that doing so doesn't get you anything, and has its costs. Commented Jan 11, 2018 at 17:12
  • I am not sure what you are saying :( Commented Jan 12, 2018 at 14:15

1 Answer 1

1

You'll need to have two overloads of the method, one that accepts a Func<IDataReader, T>, and one that accepts a Func<IDataReader, Task<T>>. The second one will need to await the method call when it invokes it, the former won't.

Sign up to request clarification or add additional context in comments.

2 Comments

That sounds fine, but won't there be a lot of repeated code?
@r3plica There's only a handful of code in the whole method, even as it sits, half of which doesn't need to be there at all, so no, not really.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.