Data Transfer Object


Como ya habia comentado en otro post, los servicios WCF van a trabajar con DTO’s, los cuales se van a generar de forma automática desde LLBLGen Pro.

Los DTO’s se van a generar como clases parciales, con dos archivos, uno para las propiedades del DTO y otro para las reglas de validación.

Se van a generar de forma que hereden de la clase DataTransferObject, la cual implementa la interface IDataModel.

   1: public interface IDataModel : IDataErrorInfo, INotifyPropertyChanged
   2: {
   3: }

La clase DataTransferObject ofrecerá una implementación por defecto para las interfaces IDataErrorInfo y INotifyPropertyChanged

   1: /// <summary>
   2: /// Base class for Data Transfer Object (DTO's) implementations.
   3: /// </summary>
   4: /// <remarks>
   5: /// See http://www.codeproject.com/KB/cs/DelegateBusinessObjects.aspx
   6: /// </remarks>
   7: [Serializable]
   8: public abstract class DataTransferObject : IDataModel
   9: {
  10:     #region · INotifyPropertyChanged Members ·
  11:  
  12:     public event PropertyChangedEventHandler PropertyChanged;
  13:  
  14:     #endregion
  15:  
  16:     #region · Fields ·
  17:     
  18:     private List<Rule> rules;
  19:     
  20:     #endregion
  21:  
  22:     #region · IDataErrorInfo Members ·
  23:  
  24:     public string Error
  25:     {
  26:         get 
  27:         {
  28:             string result = this[string.Empty];
  29:             
  30:             if (result != null && result.Trim().Length == 0) 
  31:             {
  32:                 result = null;
  33:             }
  34:             
  35:             return result;
  36:         }        
  37:     }
  38:  
  39:     public string this[string columnName]
  40:     {
  41:         get  { return this.ValidateProperty(columnName); }
  42:     }
  43:  
  44:     #endregion
  45:     
  46:     #region · Protected Properties ·
  47:     
  48:     protected List<Rule> Rules
  49:     {
  50:         get 
  51:         {
  52:             if (this.rules == null)
  53:             {
  54:                 this.rules = new List<Rule>();
  55:             }
  56:             
  57:             return this.rules;
  58:         }
  59:     }
  60:     
  61:     #endregion
  62:     
  63:     #region · Protected Validation Methods ·
  64:  
  65:     protected abstract void CreateRules();
  66:  
  67:     protected virtual IEnumerable<Rule> GetBrokenRules(string propertyName)
  68:     {
  69:         propertyName = this.CleanString(propertyName);
  70:     
  71:         if (this.Rules.Count == 0)
  72:         {
  73:             this.CreateRules();
  74:         }            
  75:             
  76:         foreach (Rule rule in this.Rules)
  77:         {
  78:             if (rule.PropertyName == propertyName || propertyName.Length == 0)
  79:             {
  80:                 if (!rule.ValidateRule())
  81:                 {
  82:                     yield return rule;
  83:                 }
  84:             }
  85:         }
  86:     }        
  87:  
  88:     protected virtual string ValidateProperty(string propertyName)
  89:     {
  90:         return this.BuildMessage(this.GetBrokenRules(propertyName));
  91:     }
  92:  
  93:     protected virtual string CleanString(string s)
  94:     {
  95:         return (s ?? string.Empty).Trim();
  96:     }
  97:  
  98:     protected virtual string BuildMessage(IEnumerable<Rule> brokenRules)
  99:     {
 100:         StringBuilder builder = new StringBuilder();
 101:  
 102:         foreach (Rule rule in brokenRules)
 103:         {
 104:             if (builder.Length > 0)
 105:             {
 106:                 builder.Append(Environment.NewLine);
 107:             }
 108:             builder.Append(rule.Description);
 109:         }
 110:  
 111:         return ((builder.ToString().Length == 0) ? null : builder.ToString());
 112:     }
 113:  
 114:     protected virtual void NotifyPropertyChanged(String propertyName)
 115:     {
 116:         if (this.PropertyChanged != null)
 117:         {
 118:             this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
 119:         }
 120:     }
 121:  
 122:     protected virtual void AddRule(string description, string propertyName, SimpleRuleDelegate ruleDelegate)
 123:     {
 124:         this.Rules.Add(new SimpleRule(description, propertyName, ruleDelegate));
 125:     }
 126:  
 127:     #endregion            
 128: }

El sistema de reglas para las validaciones de los datos está basado en el explicado aquí, así que no lo explicaré aquí.

Ahora veamos como queda el DTO de Divisas una vez generado con LLBLGen Pro

  • Divisa.cs. Tiene las propiedades para los datos de las divisas ( notificando los cambios cuando sea necesario en el momento de establecer el valor de cada propiedad ) y para sus tablas relacionadas, este archivo debería poder regenerarse cada vez así que no se harán cambios en el.
   1: /// <summary>
   2: /// DTO class for the entity 'Divisa'.
   3: /// </summary>
   4: [Serializable]
   5: [DataContract]
   6: public partial class Divisa : DataTransferObject
   7: {
   8:     #region · Fields ·
   9:     
  10:             private System.String idDivisa;
  11:     private Nullable<System.Int32> numeroDecimales;
  12:     private System.String nombreUnidadMonetariaSingular;
  13:     private System.String nombreUnidadMonetariaPlural;
  14:     private System.String nombreUnidadFraccionariaSingular;
  15:     private System.String nombreUnidadFraccionariaPlural;
  16:     private System.Byte[] lastUpdate;
  17:  
  18:     #endregion
  19:  
  20:     #region · Relation Fields ·
  21:  
  22:     
  23:  
  24:  
  25:  
  26:  
  27:     private ObservableCollection<DivisaArqueo> arqueos;
  28:     private ObservableCollection<DivisaCambio> cambios;
  29:  
  30:  
  31:  
  32:  
  33:  
  34:  
  35:  
  36:  
  37:  
  38:  
  39:  
  40:  
  41:  
  42:  
  43:  
  44:     
  45:  
  46:  
  47:  
  48:  
  49:  
  50:  
  51:  
  52:  
  53:  
  54:  
  55:  
  56:  
  57:  
  58:  
  59:  
  60:  
  61:  
  62:  
  63:  
  64:  
  65:  
  66:  
  67:  
  68:  
  69:  
  70:  
  71:  
  72:  
  73:  
  74:  
  75:  
  76:  
  77:  
  78:  
  79:  
  80:  
  81:  
  82:  
  83:  
  84:  
  85:  
  86:  
  87:  
  88:  
  89:  
  90:  
  91:  
  92:  
  93:  
  94:  
  95:  
  96:  
  97:  
  98:  
  99:  
 100:  
 101:  
 102:  
 103:  
 104:  
 105:  
 106:  
 107:  
 108:  
 109:  
 110:  
 111:  
 112:  
 113:  
 114:  
 115:  
 116:  
 117:  
 118:  
 119:  
 120:  
 121:  
 122:  
 123:  
 124:  
 125:  
 126:  
 127:  
 128:  
 129:     
 130:     
 131:  
 132:     #endregion
 133:  
 134:     #region · Properties ·
 135:     
 136:     /// <summary> 
 137:     /// The IdDivisa property of the Entity Divisa
 138:     /// </summary>
 139:     [DataMember]
 140:     public virtual System.String IdDivisa
 141:     {
 142:         get { return this.idDivisa;}
 143:         set 
 144:         {
 145:             if (this.idDivisa != value)
 146:             {
 147:                 this.idDivisa = value;
 148:                 this.NotifyPropertyChanged("IdDivisa");
 149:             }
 150:         }
 151:     }
 152:  
 153:     /// <summary> 
 154:     /// The NumeroDecimales property of the Entity Divisa
 155:     /// </summary>
 156:     [DataMember]
 157:     public virtual Nullable<System.Int32> NumeroDecimales
 158:     {
 159:         get { return this.numeroDecimales;}
 160:         set 
 161:         {
 162:             if (this.numeroDecimales != value)
 163:             {
 164:                 this.numeroDecimales = value;
 165:                 this.NotifyPropertyChanged("NumeroDecimales");
 166:             }
 167:         }
 168:     }
 169:  
 170:     /// <summary> 
 171:     /// The NombreUnidadMonetariaSingular property of the Entity Divisa
 172:     /// </summary>
 173:     [DataMember]
 174:     public virtual System.String NombreUnidadMonetariaSingular
 175:     {
 176:         get { return this.nombreUnidadMonetariaSingular;}
 177:         set 
 178:         {
 179:             if (this.nombreUnidadMonetariaSingular != value)
 180:             {
 181:                 this.nombreUnidadMonetariaSingular = value;
 182:                 this.NotifyPropertyChanged("NombreUnidadMonetariaSingular");
 183:             }
 184:         }
 185:     }
 186:  
 187:     /// <summary> 
 188:     /// The NombreUnidadMonetariaPlural property of the Entity Divisa
 189:     /// </summary>
 190:     [DataMember]
 191:     public virtual System.String NombreUnidadMonetariaPlural
 192:     {
 193:         get { return this.nombreUnidadMonetariaPlural;}
 194:         set 
 195:         {
 196:             if (this.nombreUnidadMonetariaPlural != value)
 197:             {
 198:                 this.nombreUnidadMonetariaPlural = value;
 199:                 this.NotifyPropertyChanged("NombreUnidadMonetariaPlural");
 200:             }
 201:         }
 202:     }
 203:  
 204:     /// <summary> 
 205:     /// The NombreUnidadFraccionariaSingular property of the Entity Divisa
 206:     /// </summary>
 207:     [DataMember]
 208:     public virtual System.String NombreUnidadFraccionariaSingular
 209:     {
 210:         get { return this.nombreUnidadFraccionariaSingular;}
 211:         set 
 212:         {
 213:             if (this.nombreUnidadFraccionariaSingular != value)
 214:             {
 215:                 this.nombreUnidadFraccionariaSingular = value;
 216:                 this.NotifyPropertyChanged("NombreUnidadFraccionariaSingular");
 217:             }
 218:         }
 219:     }
 220:  
 221:     /// <summary> 
 222:     /// The NombreUnidadFraccionariaPlural property of the Entity Divisa
 223:     /// </summary>
 224:     [DataMember]
 225:     public virtual System.String NombreUnidadFraccionariaPlural
 226:     {
 227:         get { return this.nombreUnidadFraccionariaPlural;}
 228:         set 
 229:         {
 230:             if (this.nombreUnidadFraccionariaPlural != value)
 231:             {
 232:                 this.nombreUnidadFraccionariaPlural = value;
 233:                 this.NotifyPropertyChanged("NombreUnidadFraccionariaPlural");
 234:             }
 235:         }
 236:     }
 237:  
 238:     /// <summary> 
 239:     /// The LastUpdate property of the Entity Divisa
 240:     /// </summary>
 241:     [DataMember]
 242:     public virtual System.Byte[] LastUpdate
 243:     {
 244:         get { return this.lastUpdate;}
 245:         set 
 246:         {
 247:             if (this.lastUpdate != value)
 248:             {
 249:                 this.lastUpdate = value;
 250:                 this.NotifyPropertyChanged("LastUpdate");
 251:             }
 252:         }
 253:     }
 254:     #endregion
 255:     
 256:     #region · Relation Properties ·
 257:     
 258:  
 259:  
 260:  
 261:  
 262:     
 263:     /// <summary>
 264:     /// Gets the EntityCollection with the related entities of type 'DivisaArqueoEntity' which are related to this entity via a relation of type '1:n'.
 265:     /// If the EntityCollection hasn't been fetched yet, the collection returned will be empty.
 266:     /// </summary>
 267:      [DataMember]
 268:     public virtual ObservableCollection<DivisaArqueo> Arqueos
 269:     {
 270:         get 
 271:         {
 272:             if (this.arqueos == null)
 273:             {
 274:                 this.arqueos = new ObservableCollection<DivisaArqueo>();
 275:             }
 276:  
 277:             return this.arqueos; 
 278:         }
 279:         set { this.arqueos = value; }
 280:     }
 281:     
 282:     /// <summary>
 283:     /// Gets the EntityCollection with the related entities of type 'DivisaCambioEntity' which are related to this entity via a relation of type '1:n'.
 284:     /// If the EntityCollection hasn't been fetched yet, the collection returned will be empty.
 285:     /// </summary>
 286:      [DataMember]
 287:     public virtual ObservableCollection<DivisaCambio> Cambios
 288:     {
 289:         get 
 290:         {
 291:             if (this.cambios == null)
 292:             {
 293:                 this.cambios = new ObservableCollection<DivisaCambio>();
 294:             }
 295:  
 296:             return this.cambios; 
 297:         }
 298:         set { this.cambios = value; }
 299:     }
 300:  
 301:  
 302:  
 303:  
 304:  
 305:  
 306:  
 307:  
 308:  
 309:  
 310:  
 311:  
 312:  
 313:  
 314:  
 315:     
 316:     
 317:  
 318:  
 319:  
 320:  
 321:  
 322:  
 323:  
 324:  
 325:  
 326:  
 327:  
 328:  
 329:  
 330:  
 331:  
 332:  
 333:  
 334:  
 335:  
 336:  
 337:  
 338:  
 339:  
 340:  
 341:  
 342:  
 343:  
 344:  
 345:  
 346:  
 347:  
 348:  
 349:  
 350:  
 351:  
 352:  
 353:  
 354:  
 355:  
 356:  
 357:  
 358:  
 359:  
 360:  
 361:  
 362:  
 363:  
 364:  
 365:  
 366:  
 367:  
 368:  
 369:  
 370:  
 371:  
 372:  
 373:  
 374:  
 375:  
 376:  
 377:  
 378:  
 379:  
 380:  
 381:  
 382:  
 383:  
 384:  
 385:  
 386:  
 387:  
 388:  
 389:  
 390:  
 391:  
 392:  
 393:  
 394:  
 395:  
 396:  
 397:  
 398:  
 399:  
 400:  
 401:     
 402:     
 403:     
 404:     
 405:  
 406:     #endregion        
 407:  
 408:     #region · Constructors ·
 409:  
 410:     /// <summary>
 411:     /// Initializes a new instance of <see cref="Divisa" />
 412:     /// </summary>
 413:     public Divisa()
 414:     {        
 415:     }
 416:     
 417:     #endregion        
 418: }
  • Divisa.br.cs. En este pondremos las reglas para la validación de los datos y una vez modificado, hay que tener cuidado ( jeje ) de no volver a generarlo por que se perderían los cambios.
   1: /// <summary>
   2: /// Bussines rules DTO class for the entity 'Divisa'.
   3: /// </summary>
   4: public partial class Divisa        
   5: {
   6:     #region · CreateRules ·
   7:  
   8:     protected override void CreateRules()
   9:     {
  10:     }
  11:     
  12:     #endregion
  13: }

Añadir una regla de validación para el Id de la divisa sería tan fácil como esto

   1: this.AddRule("Debe indicar el código de la divisa.", "IdDivisa",
   2:     delegate { return (!String.IsNullOrEmpty(this.IdDivisa) && this.IdDivisa.Length > 0); });

Devolver los datos de una divisa determinada desde un servicio de WCF sería tan sencillo como esto

   1: public Divisa Fetch(string idDivisa)
   2: {
   3:     Debug.Assert(idDivisa != null, "Debe indicar el id de la divisa.");
   4:  
   5:     using (DataAccessAdapter adapter = new DataAccessAdapter())
   6:     {
   7:         LinqMetaData metaData = new LinqMetaData(adapter);
   8:  
   9:         var q = (from c in metaData.Divisa
  10:                  where
  11:                     c.IdDivisa == idDivisa
  12:                  select c).WithPath(
  13:                             new PathEdge<DivisaCambioEntity>(DivisaEntity.PrefetchPathCambios),
  14:                             new PathEdge<DivisaArqueoEntity>(DivisaEntity.PrefetchPathArqueos));
  15:  
  16:         return ((q.Count<DivisaEntity>() > 0) ? DivisaMapper.Assemble(q.First<DivisaEntity>()) : null);
  17:     }
  18: }

En este caso se devuelven los datos de la divisa que se ha pedido y los de 2 de sus tablas relacionadas ( el código no es definitivo, pero sirve como ejemplo )


Responder

Por favor, inicia sesión con uno de estos métodos para publicar tu comentario:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s