|
19 | 19 |
|
20 | 20 | namespace Pomelo.EntityFrameworkCore.MySql.Storage.Internal |
21 | 21 | { |
| 22 | + /// <summary> |
| 23 | + /// Type mapping for complex JSON types (used when JSON is mapped to complex .NET types). |
| 24 | + /// Always converts string to MemoryStream since EF Core expects MemoryStream for complex JSON. |
| 25 | + /// </summary> |
| 26 | + public class MySqlComplexJsonTypeMapping : MySqlJsonTypeMapping<string> |
| 27 | + { |
| 28 | + public MySqlComplexJsonTypeMapping( |
| 29 | + [NotNull] string storeType, |
| 30 | + [CanBeNull] ValueConverter valueConverter, |
| 31 | + [CanBeNull] ValueComparer valueComparer, |
| 32 | + bool noBackslashEscapes, |
| 33 | + bool replaceLineBreaksWithCharFunction) |
| 34 | + : base(storeType, valueConverter, valueComparer, noBackslashEscapes, replaceLineBreaksWithCharFunction) |
| 35 | + { |
| 36 | + } |
| 37 | + |
| 38 | + protected MySqlComplexJsonTypeMapping( |
| 39 | + RelationalTypeMappingParameters parameters, |
| 40 | + MySqlDbType mySqlDbType, |
| 41 | + bool noBackslashEscapes, |
| 42 | + bool replaceLineBreaksWithCharFunction) |
| 43 | + : base(parameters, mySqlDbType, noBackslashEscapes, replaceLineBreaksWithCharFunction) |
| 44 | + { |
| 45 | + } |
| 46 | + |
| 47 | + protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters) |
| 48 | + => new MySqlComplexJsonTypeMapping(parameters, MySqlDbType, NoBackslashEscapes, ReplaceLineBreaksWithCharFunction); |
| 49 | + |
| 50 | + protected override RelationalTypeMapping Clone(bool? noBackslashEscapes = null, bool? replaceLineBreaksWithCharFunction = null) |
| 51 | + => new MySqlComplexJsonTypeMapping( |
| 52 | + Parameters, |
| 53 | + MySqlDbType, |
| 54 | + noBackslashEscapes ?? NoBackslashEscapes, |
| 55 | + replaceLineBreaksWithCharFunction ?? ReplaceLineBreaksWithCharFunction); |
| 56 | + |
| 57 | + /// <summary> |
| 58 | + /// For complex JSON, we ALWAYS convert string to MemoryStream. |
| 59 | + /// </summary> |
| 60 | + public override Expression CustomizeDataReaderExpression(Expression expression) |
| 61 | + { |
| 62 | + if (expression.Type == typeof(string)) |
| 63 | + { |
| 64 | + // Get the cached reflection members from the base class |
| 65 | + var utf8Property = typeof(System.Text.Encoding).GetProperty(nameof(System.Text.Encoding.UTF8)); |
| 66 | + var getBytesMethod = typeof(System.Text.Encoding).GetMethod(nameof(System.Text.Encoding.GetBytes), new[] { typeof(string) }); |
| 67 | + var memoryStreamCtor = typeof(System.IO.MemoryStream).GetConstructor(new[] { typeof(byte[]) }); |
| 68 | + |
| 69 | + if (utf8Property == null || getBytesMethod == null || memoryStreamCtor == null) |
| 70 | + { |
| 71 | + throw new InvalidOperationException( |
| 72 | + "Failed to find required reflection members for JSON type mapping."); |
| 73 | + } |
| 74 | + |
| 75 | + // Convert string to MemoryStream |
| 76 | + return Expression.New( |
| 77 | + memoryStreamCtor, |
| 78 | + Expression.Call( |
| 79 | + Expression.Property(null, utf8Property), |
| 80 | + getBytesMethod, |
| 81 | + expression)); |
| 82 | + } |
| 83 | + |
| 84 | + return base.CustomizeDataReaderExpression(expression); |
| 85 | + } |
| 86 | + } |
| 87 | + |
22 | 88 | public class MySqlJsonTypeMapping<T> : MySqlJsonTypeMapping |
23 | 89 | { |
24 | 90 | public static new MySqlJsonTypeMapping<T> Default { get; } = new("json", null, null, false, true); |
@@ -133,45 +199,6 @@ protected override void ConfigureParameter(DbParameter parameter) |
133 | 199 | } |
134 | 200 | } |
135 | 201 |
|
136 | | - /// <summary> |
137 | | - /// Returns the method to be used for reading JSON values from the database. |
138 | | - /// MySQL stores JSON as strings, so we use GetString instead of the default GetFieldValue<T>. |
139 | | - /// This prevents EF Core from trying to convert from string to MemoryStream for complex JSON types. |
140 | | - /// </summary> |
141 | | - public override MethodInfo GetDataReaderMethod() |
142 | | - => _getString; |
143 | | - |
144 | | - /// <summary> |
145 | | - /// Customizes the data reader expression for JSON types. |
146 | | - /// MySQL stores JSON as strings, but EF Core expects MemoryStream for complex JSON types. |
147 | | - /// We always convert string to MemoryStream since JSON type mappings are used for complex types. |
148 | | - /// </summary> |
149 | | - public override Expression CustomizeDataReaderExpression(Expression expression) |
150 | | - { |
151 | | - // Convert string to MemoryStream for JSON types. |
152 | | - // EF Core uses MemoryStream for complex JSON properties. |
153 | | - if (expression.Type == typeof(string)) |
154 | | - { |
155 | | - // Validate that reflection lookups succeeded |
156 | | - if (_utf8Property == null || _getBytesMethod == null || _memoryStreamCtor == null) |
157 | | - { |
158 | | - throw new InvalidOperationException( |
159 | | - "Failed to find required reflection members for JSON type mapping. " + |
160 | | - "This may indicate an incompatible version of the .NET runtime."); |
161 | | - } |
162 | | - |
163 | | - // Convert string to MemoryStream: new MemoryStream(Encoding.UTF8.GetBytes(stringValue)) |
164 | | - return Expression.New( |
165 | | - _memoryStreamCtor, |
166 | | - Expression.Call( |
167 | | - Expression.Property(null, _utf8Property), |
168 | | - _getBytesMethod, |
169 | | - expression)); |
170 | | - } |
171 | | - |
172 | | - return base.CustomizeDataReaderExpression(expression); |
173 | | - } |
174 | | - |
175 | 202 | void IMySqlCSharpRuntimeAnnotationTypeMappingCodeGenerator.Create( |
176 | 203 | CSharpRuntimeAnnotationCodeGeneratorParameters codeGeneratorParameters, |
177 | 204 | CSharpRuntimeAnnotationCodeGeneratorDependencies codeGeneratorDependencies) |
|
0 commit comments