1+ using System ;
2+ using System . Linq ;
3+ using System . Reflection ;
4+ using Microsoft . EntityFrameworkCore ;
5+ using Microsoft . EntityFrameworkCore . Query . SqlExpressions ;
6+
7+ namespace NBS . EntityFrameworkCore . SqlServer
8+ {
9+ /// <summary>
10+ /// Methods for calling <a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/try-parse-transact-sql" target="_blank">TRY_PARSE</a> from EF Core.
11+ /// </summary>
12+ /// <example>
13+ /// <para>Register the extension in the <c>OnModelCreating</c> method:</para>
14+ /// <code>
15+ /// protected override void OnModelCreating(ModelBuilder modelBuilder)
16+ /// {
17+ /// base.OnModelCreating(modelBuilder);
18+ /// TryParse.Register(modelBuilder);
19+ /// }
20+ /// </code>
21+ /// <para>You can then call the functions as part of a query against this context:</para>
22+ /// <code>
23+ /// var results = context.SomeSet.Select(e => new { e.Id, e.Name, ValueInt32 = TryParse.Int32(e.Value) }).ToList();
24+ /// </code>
25+ /// <para>This will be translated into a suitable SQL query:</para>
26+ /// <code>
27+ /// SELECT Id, Name, TRY_PARSE(Value As int) As ValueInt32 FROM SomeSet
28+ /// </code>
29+ /// </example>
30+ public static class TryParse
31+ {
32+ /// <summary>
33+ /// Registers the <c>TRY_PARSE</c> functions.
34+ /// </summary>
35+ /// <param name="modelBuilder">
36+ /// The <see cref="ModelBuilder"/>.
37+ /// </param>
38+ /// <exception cref="ArgumentNullException">
39+ /// <paramref name="modelBuilder"/> is <see langword="null"/>.
40+ /// </exception>
41+ public static void Register ( ModelBuilder modelBuilder )
42+ {
43+ if ( modelBuilder is null ) throw new ArgumentNullException ( nameof ( modelBuilder ) ) ;
44+
45+ foreach ( var dbFunc in typeof ( TryParse ) . GetMethods ( BindingFlags . Public | BindingFlags . Static ) )
46+ {
47+ var attribute = dbFunc . GetCustomAttribute < SqlTypeNameAttribute > ( ) ;
48+ if ( attribute is null ) continue ;
49+
50+ modelBuilder . HasDbFunction ( dbFunc ) . HasTranslation ( args =>
51+ {
52+ var newArgs = args . ToList ( ) ;
53+ newArgs [ 0 ] = new TryParseArgumentExpression ( dbFunc . ReturnType , newArgs [ 0 ] , attribute . SqlTypeName ) ;
54+ return SqlFunctionExpression . Create ( "TRY_PARSE" , newArgs , dbFunc . ReturnType , null ) ;
55+ } ) ;
56+ }
57+ }
58+
59+ /// <summary>
60+ /// Attempts to parse the string as a byte.
61+ /// </summary>
62+ /// <param name="value">The string value to parse.</param>
63+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
64+ [ SqlTypeName ( "tinyint" ) ]
65+ public static byte ? Byte ( string value ) => byte . TryParse ( value , out var result ) ? result : null ;
66+
67+ /// <summary>
68+ /// Attempts to parse the string as a 16-bit integer.
69+ /// </summary>
70+ /// <param name="value">The string value to parse.</param>
71+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
72+ [ SqlTypeName ( "smallint" ) ]
73+ public static short ? Int16 ( string value ) => short . TryParse ( value , out var result ) ? result : null ;
74+
75+ /// <summary>
76+ /// Attempts to parse the string as a 32-bit integer.
77+ /// </summary>
78+ /// <param name="value">The string value to parse.</param>
79+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
80+ [ SqlTypeName ( "int" ) ]
81+ public static int ? Int32 ( string value ) => int . TryParse ( value , out var result ) ? result : null ;
82+
83+ /// <summary>
84+ /// Attempts to parse the string as a 64-bit integer.
85+ /// </summary>
86+ /// <param name="value">The string value to parse.</param>
87+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
88+ [ SqlTypeName ( "bigint" ) ]
89+ public static long ? Int64 ( string value ) => long . TryParse ( value , out var result ) ? result : null ;
90+
91+ /// <summary>
92+ /// Attempts to parse the string as a decimal.
93+ /// </summary>
94+ /// <param name="value">The string value to parse.</param>
95+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
96+ [ SqlTypeName ( "decimal" ) ]
97+ public static decimal ? Decimal ( string value ) => decimal . TryParse ( value , out var result ) ? result : null ;
98+
99+ /// <summary>
100+ /// Attempts to parse the string as a double-precision floating-point number.
101+ /// </summary>
102+ /// <param name="value">The string value to parse.</param>
103+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
104+ [ SqlTypeName ( "float" ) ]
105+ public static double ? Double ( string value ) => double . TryParse ( value , out var result ) ? result : null ;
106+
107+ /// <summary>
108+ /// Attempts to parse the string as a single-precision floating-point number.
109+ /// </summary>
110+ /// <param name="value">The string value to parse.</param>
111+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
112+ [ SqlTypeName ( "real" ) ]
113+ public static float ? Single ( string value ) => float . TryParse ( value , out var result ) ? result : null ;
114+
115+ /// <summary>
116+ /// Attempts to parse the string as a date.
117+ /// </summary>
118+ /// <param name="value">The string value to parse.</param>
119+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
120+ [ SqlTypeName ( "date" ) ]
121+ public static DateTime ? Date ( string value ) => System . DateTime . TryParse ( value , out var result ) ? result : null ;
122+
123+ /// <summary>
124+ /// Attempts to parse the string as a <see cref="System.DateTime"/>.
125+ /// </summary>
126+ /// <param name="value">The string value to parse.</param>
127+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
128+ [ SqlTypeName ( "datetime2" ) ]
129+ public static DateTime ? DateTime ( string value ) => System . DateTime . TryParse ( value , out var result ) ? result : null ;
130+
131+ /// <summary>
132+ /// Attempts to parse the string as a <see cref="System.DateTimeOffset"/>.
133+ /// </summary>
134+ /// <param name="value">The string value to parse.</param>
135+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
136+ [ SqlTypeName ( "datetimeoffset" ) ]
137+ public static DateTimeOffset ? DateTimeOffset ( string value ) => System . DateTimeOffset . TryParse ( value , out var result ) ? result : null ;
138+
139+ /// <summary>
140+ /// Attempts to parse the string as a time.
141+ /// </summary>
142+ /// <param name="value">The string value to parse.</param>
143+ /// <returns>The parsed value, if available; otherwise, <see langword="null"/></returns>
144+ [ SqlTypeName ( "time" ) ]
145+ public static TimeSpan ? Time ( string value ) => TimeSpan . TryParse ( value , out var result ) ? result : null ;
146+ }
147+ }
0 commit comments