1

I have method which return List and I wanna try to populate ValueTuple from another standard list I get error:

Cannot implicitly convert type 'System.Collections.Generic.List<(long PaymentId, long TransactionId)>' to 'System.Collections.Generic.List>'

The code looks like below:

public async Task<List<ValueTuple<(long, long)>>> CreditTransactionAsync(CancellationToken cancellationToken)
{
 List<(long PaymentId, long TransactionId)> paymentTransactionList = new List<ValueTuple<long, long>>();

 var paymentTransactions = _dbContext.PaymentTransactions
                                .AsEnumerable()
                                .Where(x => transactionIdsList.Any(a => a.TransactionId == x.TransactionId))
                                .Select(x => new
                                 {
                                   PaymentId = x.PaymentId,
                                   TransactionId = x.TransactionId
                                 })
                                .ToList();
// This line shows error..
 paymentTransactionList = paymentTransactions.Select(x => (PaymentId: x.PaymentId, TransactionId: x.TransactionId));

 return paymentTransactionList;
}
esnezz
  • 619
  • 1
  • 7
  • 19
redux17
  • 665
  • 5
  • 11
  • 30

2 Answers2

4

You can rewrite your Select statement a little bit and map transactions to list of tuple (long, long) directly, without intermediate anonymous type

.Select(x => (x.PaymentId, x.TransactionId))

The full code

var paymentTransactions = _dbContext.PaymentTransactions
                                .AsEnumerable()
                                .Where(x => transactionIdsList.Any(a => a.TransactionId == x.TransactionId))
                                .Select(x => (x.PaymentId, x.TransactionId))
                                .ToList();
return paymentTransactions;

You also should properly declare the return type of your method, like Task<List<(long paymentId, long transactionId)>>

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66
  • I did it before but that works like Tuple not ValueTuple and I have to access list members as tupleList.Item1 and tuppleList.Item2 insterad of tuppleList.PaymentId, tuppleList.TransarctionId – redux17 Jun 05 '20 at 10:58
  • @redux17 I see, you should use proper declaration in return type, like `List<(long paymentId, long transactionId)>` – Pavel Anikhouski Jun 05 '20 at 11:07
  • Note: this will fetch the entire `PaymentTransactions` table into local memory – Marc Gravell Jun 05 '20 at 11:33
  • @MarcGravell thanks, it's a really good point! OP can use `.AsEnumerable()` after filtering the records using `Where`. However, the optimization of this query is a different problem from original one, posted in question – Pavel Anikhouski Jun 05 '20 at 11:47
  • @redux17 Does it answer your question, do you need more details or information? – Pavel Anikhouski Jun 08 '20 at 07:43
  • @Pavel No, I don't. It's enough thank you so much for your answers. – redux17 Jun 08 '20 at 11:04
3

ValueTuple<(long, long)> is a value tuple that contains a single element that is a value tuple that contains two elements.

You probably meant List<(long, long)>, not List<ValueTuple<(long, long)>>, however personally I'd say "don't use ValueTuple<...> on public APIs", but if you do: at least name them.

Also: AsEnumerable() on a db-context is usually a terrible mistake - especially before a Where:


public async Task<List<(long PaymentId, long TransactionId)>> CreditTransactionAsync(CancellationToken cancellationToken = default)
{
    var localList = transactionIdsList.Select(a => a.TransactionId).ToList();
    return _dbContext.PaymentTransactions
                .Where(x => localList.Contains(x.TransactionId))
                .Select(x => new { x.PaymentId, x.TransactionId })
                .AsEnumerable()
                .Select(x => (x.PaymentId, x.TransactionId))
                .ToList();
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • @March Thank you for your comment. I had to use AsNumerable() becauuse LINQ throw exception when i do filter witt Any() inside Where clause – redux17 Jun 05 '20 at 11:01
  • @redux17 I've made a few other tweaks to try to make it happy - see above – Marc Gravell Jun 05 '20 at 11:02
  • @redux17 also - there's nothing async in your async method; that usually means there's a problem? – Marc Gravell Jun 05 '20 at 11:04
  • @March Gravell I applied your snippet code it'works but you had to use AsNumerable() again ? Regarding async..I used it for await _dbContext.PaymentTransactions and ToListAsync(cancellationToken) but not working with AsAyncNumerable() so have to change return method type – redux17 Jun 05 '20 at 11:16
  • @redux17 that's because the compiler won't let me use value-tuple construction in a lambda expression, and `IQueryable` uses lambda expressions; it is fine in an anonymous method, though; so **after** we've composed the query (the `Where` filter and the `Select` projection), we can switch to LINQ-to-Objects for the final projection to value-tuples. Note that this wouldn't be necessary if you were using your own custom type for the return, instead of value-tuples - you could lose the `.AsEnumerable()` and the extra `Select`, and go straight to your custom type – Marc Gravell Jun 05 '20 at 11:33
  • Thank you so much @March I'm gonna change it to dto object and skip this part with Select => AsNumerable() – redux17 Jun 05 '20 at 11:53