| | 1 | | using System.ComponentModel.DataAnnotations; |
| | 2 | | using System.ComponentModel.DataAnnotations.Schema; |
| | 3 | | using System.Data; |
| | 4 | | using System.Text.Json; |
| | 5 | | using System.Text.Json.Serialization; |
| | 6 | | using Common.Core.Classes; |
| | 7 | | using Common.Core.Converters; |
| | 8 | | using Common.Core.Interfaces; |
| | 9 | |
|
| | 10 | | namespace Common.Core.Models; |
| | 11 | |
|
| | 12 | | /// <summary>This class contains details of a Person.</summary> |
| | 13 | | public class Person : ModelEdit, IPerson |
| | 14 | | { |
| | 15 | | /// <summary>Default name of the Person data file.</summary> |
| | 16 | | public const string cDefaultFile = "Person.json"; |
| | 17 | |
|
| | 18 | | #region Private Variables |
| | 19 | |
|
| | 20 | | private int _id; |
| | 21 | | private string? _firstName; |
| | 22 | | private string? _middleName; |
| | 23 | | private string? _lastName; |
| 30 | 24 | | private Address _address = new(); |
| | 25 | | private string? _governmentNumber; |
| | 26 | | private string? _idProvince; |
| | 27 | | private string? _idNumber; |
| | 28 | | private string? _homePhone; |
| | 29 | | private DateOnly? _birthDate; |
| | 30 | |
|
| | 31 | | #endregion |
| | 32 | |
|
| | 33 | | #region IPerson Properties |
| | 34 | |
|
| | 35 | | /// <inheritdoc/> |
| | 36 | | public override int Id |
| | 37 | | { |
| 50 | 38 | | get => _id; |
| | 39 | | set |
| 31 | 40 | | { |
| 31 | 41 | | if( value != _id ) |
| 30 | 42 | | { |
| 30 | 43 | | _id = value; |
| 30 | 44 | | OnPropertyChanged( nameof( Id ) ); |
| 30 | 45 | | } |
| 31 | 46 | | } |
| | 47 | | } |
| | 48 | |
|
| | 49 | | /// <inheritdoc/> |
| | 50 | | [Required] |
| | 51 | | [MaxLength( 50 )] |
| | 52 | | public string FirstName |
| | 53 | | { |
| 50 | 54 | | get => ( _firstName is not null ) ? _firstName : string.Empty; |
| | 55 | | set |
| 31 | 56 | | { |
| 31 | 57 | | if( !value.Equals( _firstName ) ) |
| 31 | 58 | | { |
| 31 | 59 | | _firstName = value; |
| 31 | 60 | | OnPropertyChanged( nameof( FirstName ) ); |
| 31 | 61 | | OnPropertyChanged( nameof( FullName ) ); |
| 31 | 62 | | } |
| 31 | 63 | | } |
| | 64 | | } |
| | 65 | |
|
| | 66 | | /// <inheritdoc/> |
| | 67 | | [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )] |
| | 68 | | [MaxLength( 50 )] |
| | 69 | | public string? MiddleName |
| | 70 | | { |
| 46 | 71 | | get => _middleName; |
| | 72 | | set |
| 31 | 73 | | { |
| 31 | 74 | | if( value != _middleName ) |
| 11 | 75 | | { |
| 11 | 76 | | _middleName = SetNullString( value ); |
| 11 | 77 | | OnPropertyChanged( nameof( MiddleName ) ); |
| 11 | 78 | | OnPropertyChanged( nameof( FullName ) ); |
| 11 | 79 | | } |
| 31 | 80 | | } |
| | 81 | | } |
| | 82 | |
|
| | 83 | | /// <inheritdoc/> |
| | 84 | | [Required] |
| | 85 | | [MaxLength( 50 )] |
| | 86 | | public string LastName |
| | 87 | | { |
| 46 | 88 | | get => ( _lastName is not null ) ? _lastName : string.Empty; |
| | 89 | | set |
| 31 | 90 | | { |
| 31 | 91 | | if( !value.Equals( _lastName ) ) |
| 31 | 92 | | { |
| 31 | 93 | | _lastName = value; |
| 31 | 94 | | OnPropertyChanged( nameof( LastName ) ); |
| 31 | 95 | | OnPropertyChanged( nameof( FullName ) ); |
| 31 | 96 | | } |
| 31 | 97 | | } |
| | 98 | | } |
| | 99 | |
|
| | 100 | | /// <inheritdoc/> |
| | 101 | | public Address Address |
| | 102 | | { |
| 36 | 103 | | get => _address; |
| | 104 | | set |
| 28 | 105 | | { |
| 28 | 106 | | if( value != _address ) |
| 28 | 107 | | { |
| 28 | 108 | | _address = value; |
| 28 | 109 | | OnPropertyChanged( nameof( Address ) ); |
| 28 | 110 | | } |
| 28 | 111 | | } |
| | 112 | | } |
| | 113 | |
|
| | 114 | | /// <inheritdoc/> |
| | 115 | | [MaxLength( 50 )] |
| | 116 | | [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )] |
| | 117 | | public string? GovernmentNumber |
| | 118 | | { |
| 19 | 119 | | get => _governmentNumber; |
| | 120 | | set |
| 31 | 121 | | { |
| 31 | 122 | | if( value != _governmentNumber ) |
| 31 | 123 | | { |
| 31 | 124 | | _governmentNumber = SetNullString( value ); |
| 31 | 125 | | OnPropertyChanged( nameof( GovernmentNumber ) ); |
| 31 | 126 | | } |
| 31 | 127 | | } |
| | 128 | | } |
| | 129 | |
|
| | 130 | | /// <inheritdoc/> |
| | 131 | | [MaxLength( 50 )] |
| | 132 | | [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )] |
| | 133 | | public string? IdProvince |
| | 134 | | { |
| 19 | 135 | | get => _idProvince; |
| | 136 | | set |
| 31 | 137 | | { |
| 31 | 138 | | if( value != _idProvince ) |
| 31 | 139 | | { |
| 31 | 140 | | _idProvince = SetNullString( value ); |
| 31 | 141 | | OnPropertyChanged( nameof( IdProvince ) ); |
| 31 | 142 | | } |
| 31 | 143 | | } |
| | 144 | | } |
| | 145 | |
|
| | 146 | | /// <inheritdoc/> |
| | 147 | | [MaxLength( 50 )] |
| | 148 | | [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )] |
| | 149 | | public string? IdNumber |
| | 150 | | { |
| 19 | 151 | | get => _idNumber; |
| | 152 | | set |
| 31 | 153 | | { |
| 31 | 154 | | if( value != _idNumber ) |
| 31 | 155 | | { |
| 31 | 156 | | _idNumber = SetNullString( value ); |
| 31 | 157 | | OnPropertyChanged( nameof( IdNumber ) ); |
| 31 | 158 | | } |
| 31 | 159 | | } |
| | 160 | | } |
| | 161 | |
|
| | 162 | | /// <inheritdoc/> |
| | 163 | | [MaxLength( 50 )] |
| | 164 | | [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )] |
| | 165 | | public string? HomePhone |
| | 166 | | { |
| 18 | 167 | | get => _homePhone; |
| | 168 | | set |
| 30 | 169 | | { |
| 30 | 170 | | if( value != _homePhone ) |
| 23 | 171 | | { |
| 23 | 172 | | _homePhone = SetNullString( value ); |
| 23 | 173 | | OnPropertyChanged( nameof( HomePhone ) ); |
| 23 | 174 | | } |
| 30 | 175 | | } |
| | 176 | | } |
| | 177 | |
|
| | 178 | | /// <inheritdoc/> |
| | 179 | | [Column( TypeName = "date" )] |
| | 180 | | [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )] |
| | 181 | | [JsonConverter( typeof( JsonDateOnlyString ) )] |
| | 182 | | public DateOnly? BirthDate |
| | 183 | | { |
| 24 | 184 | | get => _birthDate; |
| | 185 | | set |
| 32 | 186 | | { |
| 32 | 187 | | if( !value.Equals( _birthDate ) ) |
| 32 | 188 | | { |
| 32 | 189 | | _birthDate = value; |
| 32 | 190 | | OnPropertyChanged( nameof( BirthDate ) ); |
| 32 | 191 | | } |
| 32 | 192 | | } |
| | 193 | | } |
| | 194 | |
|
| | 195 | | /// <inheritdoc/> |
| | 196 | | [NotMapped] |
| | 197 | | [JsonIgnore] |
| | 198 | | public string FullName |
| | 199 | | { |
| | 200 | | get |
| 3 | 201 | | { |
| 3 | 202 | | var values = new[] { FirstName.Trim(), MiddleName?.Trim(), LastName.Trim() }; |
| 12 | 203 | | return string.Join( " ", values.Where( s => !string.IsNullOrEmpty( s ) ) ); |
| 3 | 204 | | } |
| | 205 | | } |
| | 206 | |
|
| | 207 | | #endregion |
| | 208 | |
|
| | 209 | | #region Public Methods |
| | 210 | |
|
| | 211 | | /// <inheritdoc/> |
| | 212 | | public override object Clone() |
| 3 | 213 | | { |
| 3 | 214 | | return ReflectionHelper.CreateDeepCopy( this ) as Person ?? new Person(); |
| 3 | 215 | | } |
| | 216 | |
|
| | 217 | | /// <inheritdoc/> |
| | 218 | | /// <param name="obj">An object implementing the IPerson interface to compare with this object.</param> |
| | 219 | | public override bool Equals( object? obj ) |
| 16 | 220 | | { |
| 20 | 221 | | if( obj is null || obj is not IPerson other ) { return false; } |
| 14 | 222 | | return ReflectionHelper.IsEqual( this, other ); |
| 16 | 223 | | } |
| | 224 | |
|
| | 225 | | /// <inheritdoc/> |
| | 226 | | /// <param name="obj">An object implementing the IPerson interface with the changed values.</param> |
| | 227 | | public override void Update( object? obj ) |
| 3 | 228 | | { |
| 7 | 229 | | if( obj is null || obj is not IPerson other || other is not Person person ) { return; } |
| | 230 | |
|
| 1 | 231 | | ReflectionHelper.ApplyChanges( person, this ); |
| 3 | 232 | | } |
| | 233 | |
|
| | 234 | | /// <summary>Gets the Json serializer options for Person objects.</summary> |
| | 235 | | /// <returns>A JsonSerializerOptions object.</returns> |
| | 236 | | public static JsonSerializerOptions GetSerializerOptions() |
| 1 | 237 | | { |
| 1 | 238 | | var rtn = JsonHelper.DefaultSerializerOptions(); |
| 1 | 239 | | rtn.Converters.Add( new InterfaceFactory( typeof( Person ), typeof( IPerson ) ) ); |
| 1 | 240 | | rtn.NumberHandling = JsonNumberHandling.AllowReadingFromString; |
| | 241 | |
|
| 1 | 242 | | return rtn; |
| 1 | 243 | | } |
| | 244 | |
|
| | 245 | | /// <summary>Builds a Person object from a database table row.</summary> |
| | 246 | | /// <param name="row">Database row containing the Person columns.</param> |
| | 247 | | /// <param name="addPrefix">Table column prefix for Address fields if required.</param> |
| | 248 | | /// <returns>Person object containing the database values.</returns> |
| | 249 | | /// <remarks>This method assumes that the table column names are the same as the property names.</remarks> |
| | 250 | | public static Person Read( DataRow row, string addPrefix = "" ) |
| 7 | 251 | | { |
| 7 | 252 | | return new Person() |
| 7 | 253 | | { |
| 7 | 254 | | Id = row.Field<int>( nameof( Id ) ), |
| 7 | 255 | | FirstName = row.Field<string>( nameof( FirstName ) )!, |
| 7 | 256 | | MiddleName = row.Field<string?>( nameof( MiddleName ) ), |
| 7 | 257 | | LastName = row.Field<string>( nameof( LastName ) )!, |
| 7 | 258 | | Address = Address.BuildAddress( row, addPrefix ), |
| 7 | 259 | | GovernmentNumber = row.Field<string?>( nameof( GovernmentNumber ) ), |
| 7 | 260 | | IdProvince = row.Field<string?>( nameof( IdProvince ) ), |
| 7 | 261 | | IdNumber = row.Field<string?>( nameof( IdNumber ) ), |
| 7 | 262 | | HomePhone = row.Field<string?>( nameof( HomePhone ) ), |
| 7 | 263 | | BirthDate = DateOnly.FromDateTime( row.Field<DateTime>( nameof( BirthDate ) ) ) |
| 7 | 264 | | }; |
| 7 | 265 | | } |
| | 266 | |
|
| | 267 | | /// <summary>Builds the SQL script for any value changes.</summary> |
| | 268 | | /// <param name="row">Database row containing the current Person data.</param> |
| | 269 | | /// <param name="obj">IPerson object containing the original values.</param> |
| | 270 | | /// <param name="mod">IPerson object containing the modified values.</param> |
| | 271 | | /// <param name="addPrefix">Table column name prefix for Address fields (if required).</param> |
| | 272 | | /// <returns>An empty string is returned if no changes were found.</returns> |
| | 273 | | /// <remarks>This method assumes that the table column names are the same as the property names.</remarks> |
| | 274 | | public static string UpdateSQL( DataRow row, IPerson obj, IPerson mod, string addPrefix = "" ) |
| 4 | 275 | | { |
| 4 | 276 | | IList<string> sql = new List<string>(); |
| 4 | 277 | | Person cur = Read( row, addPrefix ); |
| 6 | 278 | | if( cur.Id != mod.Id ) { return string.Empty; } |
| | 279 | |
|
| 3 | 280 | | if( !cur.Equals( obj ) ) |
| 1 | 281 | | { |
| 1 | 282 | | mod.FirstName = cur.FirstName; |
| 1 | 283 | | mod.MiddleName = cur.MiddleName; |
| 1 | 284 | | mod.LastName = cur.LastName; |
| 1 | 285 | | mod.Address = cur.Address; |
| 1 | 286 | | mod.GovernmentNumber = cur.GovernmentNumber; |
| 1 | 287 | | mod.IdProvince = cur.IdProvince; |
| 1 | 288 | | mod.IdNumber = cur.IdNumber; |
| 1 | 289 | | mod.BirthDate = cur.BirthDate; |
| 1 | 290 | | return string.Empty; |
| | 291 | | } |
| | 292 | |
|
| 8 | 293 | | if( obj.FirstName != mod.FirstName ) { SetSQLColumn( nameof( FirstName ), mod.FirstName, sql ); } |
| 8 | 294 | | if( obj.MiddleName != mod.MiddleName ) { SetSQLColumn( nameof( MiddleName ), mod.MiddleName, sql ); } |
| 8 | 295 | | if( obj.LastName != mod.LastName ) { SetSQLColumn( nameof( LastName ), mod.LastName, sql ); } |
| 2 | 296 | | _ = Address.UpdateAddress( obj.Address, mod.Address, cur.Address, sql, addPrefix ); |
| 2 | 297 | | UpdateOthers( obj, mod, sql ); |
| | 298 | |
|
| 2 | 299 | | return string.Join( ", ", sql ); |
| 4 | 300 | | } |
| | 301 | |
|
| | 302 | | #endregion |
| | 303 | |
|
| | 304 | | private static void UpdateOthers( IPerson obj, IPerson mod, IList<string> sql ) |
| 2 | 305 | | { |
| 8 | 306 | | if( obj.GovernmentNumber != mod.GovernmentNumber ) { SetSQLColumn( nameof( GovernmentNumber ), mod.GovernmentNumber, |
| 8 | 307 | | if( obj.IdProvince != mod.IdProvince ) { SetSQLColumn( nameof( IdProvince ), mod.IdProvince, sql ); } |
| 8 | 308 | | if( obj.IdNumber != mod.IdNumber ) { SetSQLColumn( nameof( IdNumber ), mod.IdNumber, sql ); } |
| 8 | 309 | | if( obj.HomePhone != mod.HomePhone ) { SetSQLColumn( nameof( HomePhone ), mod.HomePhone, sql ); } |
| 2 | 310 | | if( !obj.BirthDate.Equals( mod.BirthDate ) ) |
| 2 | 311 | | { |
| | 312 | | // Special handling for DateOnly format |
| 2 | 313 | | string? val = mod.BirthDate?.ToString( "yyyy-MM-dd" ); |
| 2 | 314 | | SetSQLColumn( nameof( BirthDate ), val, sql ); |
| 2 | 315 | | } |
| 2 | 316 | | } |
| | 317 | | } |