diff --git a/src/EFCore.Design/Design/Internal/CSharpHelper.cs b/src/EFCore.Design/Design/Internal/CSharpHelper.cs index 3a70b1cf5b0..9e6b0087b92 100644 --- a/src/EFCore.Design/Design/Internal/CSharpHelper.cs +++ b/src/EFCore.Design/Design/Internal/CSharpHelper.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Globalization; using System.Numerics; +using System.Runtime.CompilerServices; using System.Security; using System.Text; using Microsoft.EntityFrameworkCore.Internal; @@ -693,6 +694,37 @@ private string Array(Type type, IEnumerable values, bool vertical = false) return builder.ToString(); } + private string ValueTuple(ITuple tuple) + { + var builder = new StringBuilder(); + + if (tuple.Length == 1) + { + builder + .Append("ValueTuple.Create(") + .Append(UnknownLiteral(tuple[0])) + .Append(')'); + + return builder.ToString(); + } + + builder.Append('('); + + for (var i = 0; i < tuple.Length; i++) + { + if (i > 0) + { + builder.Append(", "); + } + + builder.Append(UnknownLiteral(tuple[i])); + } + + builder.Append(')'); + + return builder.ToString(); + } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -970,6 +1002,12 @@ public virtual string UnknownLiteral(object? value) return Array(literalType.GetElementType()!, array); } + if (value is ITuple tuple + && value.GetType().FullName?.StartsWith("System.ValueTuple`", StringComparison.Ordinal) == true) + { + return ValueTuple(tuple); + } + var valueType = value.GetType(); if (valueType.IsGenericType && !valueType.IsGenericTypeDefinition) { diff --git a/test/EFCore.Design.Tests/Design/Internal/CSharpHelperTest.cs b/test/EFCore.Design.Tests/Design/Internal/CSharpHelperTest.cs index e2914637c71..d551ede300e 100644 --- a/test/EFCore.Design.Tests/Design/Internal/CSharpHelperTest.cs +++ b/test/EFCore.Design.Tests/Design/Internal/CSharpHelperTest.cs @@ -183,6 +183,18 @@ public void Literal_works_when_multiline_string() "multi-line\r\nstring\nwith\r\"", "\"multi-line\\r\\nstring\\nwith\\r\\\"\""); + [ConditionalFact] + public void Literal_works_when_value_tuple() + => Literal_works((1, "hello"), "(1, \"hello\")"); + + [ConditionalFact] + public void Literal_works_when_value_tuple_of_length_1() + => Literal_works(ValueTuple.Create(1), "ValueTuple.Create(1)"); + + [ConditionalFact] + public void Literal_works_when_value_tuple_of_length_9() + => Literal_works((1, 2, 3, 4, 5, 6, 7, 8, 9), "(1, 2, 3, 4, 5, 6, 7, 8, 9)"); + [ConditionalFact] [UseCulture("de-DE")] public void Literal_works_when_DateTime()