Archivos para 8/07/08

08
Jul
08

Respondiendo a la barra de herramientas

Para hacer que la vista refleje responda a las acciones realizadas la hacer click en la barra de herramientashe utilizado el CompositeCommand de CompositeWPF, para ello he definido una clase con un comando por cada uno de los botones de la barra de herramientas

   1: public static class GeneralCommands
   2: {
   3:     #region · Static Commands ·
   4:  
   5:     public static CompositeCommand AddNewCommand    = new CompositeCommand(true);
   6:     public static CompositeCommand EditCommand      = new CompositeCommand(true);
   7:     public static CompositeCommand DeleteCommand    = new CompositeCommand(true);
   8:     public static CompositeCommand SaveCommand      = new CompositeCommand(true);
   9:     public static CompositeCommand SaveAllCommand   = new CompositeCommand(true);
  10:     public static CompositeCommand DiscardCommand   = new CompositeCommand(true);
  11:     public static CompositeCommand RefreshCommand   = new CompositeCommand(true);
  12:     public static CompositeCommand SearchCommand    = new CompositeCommand(true);
  13:     public static CompositeCommand PrintCommand     = new CompositeCommand(true);
  14:     public static CompositeCommand CloseCommand     = new CompositeCommand(true);
  15:     public static CompositeCommand CloseAllCommand  = new CompositeCommand(true);
  16:  
  17:     #endregion
  18: }

Y una clase que ejerce de proxy para acceder a los comandos ( según lo que he visto en la documentación de CompositeWPF esta clase debería servir también para facilitar los tests unitarios

   1: public class GeneralCommandsProxy
   2: {
   3:     #region · Properties ·
   4:  
   5:     public virtual CompositeCommand AddNewCommand
   6:     {
   7:         get { return GeneralCommands.AddNewCommand; }
   8:     }
   9:  
  10:     public virtual CompositeCommand EditCommand
  11:     {
  12:         get { return GeneralCommands.EditCommand; }
  13:     }
  14:  
  15:     public virtual CompositeCommand DeleteCommand
  16:     {
  17:         get { return GeneralCommands.DeleteCommand; }
  18:     }
  19:  
  20:     public virtual CompositeCommand SaveCommand
  21:     {
  22:         get { return GeneralCommands.SaveCommand; }
  23:     }
  24:  
  25:     public virtual CompositeCommand SaveAllCommand
  26:     {
  27:         get { return GeneralCommands.SaveAllCommand; }
  28:     }
  29:  
  30:     public virtual CompositeCommand DiscardCommand
  31:     {
  32:         get { return GeneralCommands.DiscardCommand; }
  33:     }
  34:  
  35:     public virtual CompositeCommand RefreshCommand
  36:     {
  37:         get { return GeneralCommands.RefreshCommand; }
  38:     }
  39:  
  40:     public virtual CompositeCommand SearchCommand
  41:     {
  42:         get { return GeneralCommands.SearchCommand; }
  43:     }
  44:  
  45:     public virtual CompositeCommand PrintCommand
  46:     {
  47:         get { return GeneralCommands.PrintCommand; }
  48:     }
  49:  
  50:     public virtual CompositeCommand CloseCommand
  51:     {
  52:         get { return GeneralCommands.CloseCommand; }
  53:     }
  54:  
  55:     public virtual CompositeCommand CloseAllCommand
  56:     {
  57:         get { return GeneralCommands.CloseAllCommand; }
  58:     }
  59:  
  60:     #endregion
  61: }

Como estoy usando ( o intentándolo ) el patro Model-View-ViewModel para la implementación de las vistas, la ejecución de las acciones se realiza en la clase ViewModel, que es una clase abstract para las implementaciones del ViewModel de cada vista de la aplicación.

   1: public abstract class ViewModel<TDataModel> : IViewModel
   2:     where TDataModel : DataTransferObject, new()

Dispone de propiedades definidas como DelegateCommand<object> ( DelegateCommand también pertenece a CompositeWPF ) por cada uno de los comandos disponibles

   1: /// <summary>
   2: /// Gets or sets the add new command.
   3: /// </summary>
   4: /// <value>The add new command.</value>
   5: public DelegateCommand<object> AddNewCommand
   6: {
   7:     get;
   8:     private set;
   9: }
  10:  
  11: /// <summary>
  12: /// Gets or sets the edit command.
  13: /// </summary>
  14: /// <value>The edit command.</value>
  15: public DelegateCommand<object> EditCommand
  16: {
  17:     get;
  18:     private set;
  19: }
  20:  
  21: /// <summary>
  22: /// Gets or sets the delete command.
  23: /// </summary>
  24: /// <value>The delete command.</value>
  25: public DelegateCommand<object> DeleteCommand
  26: {
  27:     get;
  28:     private set;
  29: }
  30:  
  31: /// <summary>
  32: /// Gets or sets the save command.
  33: /// </summary>
  34: /// <value>The save command.</value>
  35: public DelegateCommand<object> SaveCommand
  36: {
  37:     get;
  38:     private set;
  39: }
  40:  
  41: /// <summary>
  42: /// Gets or sets the discard command.
  43: /// </summary>
  44: /// <value>The discard command.</value>
  45: public DelegateCommand<object> DiscardCommand
  46: {
  47:     get;
  48:     private set;
  49: }
  50:  
  51: /// <summary>
  52: /// Gets or sets the refresh command.
  53: /// </summary>
  54: /// <value>The refresh command.</value>
  55: public DelegateCommand<object> RefreshCommand
  56: {
  57:     get;
  58:     private set;
  59: }
  60:  
  61: /// <summary>
  62: /// Gets or sets the search command.
  63: /// </summary>
  64: /// <value>The search command.</value>
  65: public DelegateCommand<object> SearchCommand
  66: {
  67:     get;
  68:     private set;
  69: }
  70:  
  71: /// <summary>
  72: /// Gets or sets the print command.
  73: /// </summary>
  74: /// <value>The print command.</value>
  75: public DelegateCommand<object> PrintCommand
  76: {
  77:     get;
  78:     private set;
  79: }
  80:  
  81:  
  82: /// <summary>
  83: /// Gets or sets the close command.
  84: /// </summary>
  85: /// <value>The close command.</value>
  86: public DelegateCommand<object> CloseCommand
  87: {
  88:     get;
  89:     private set;
  90: }
  91:  
  92: /// <summary>
  93: /// Gets or sets the close all command.
  94: /// </summary>
  95: /// <value>The close all command.</value>
  96: public DelegateCommand<object> CloseAllCommand
  97: {
  98:     get;
  99:     private set;
 100: }

Además dispone de métodos para inicializar y registrar los comandos

   1: /// <summary>
   2: /// Initializes the commands.
   3: /// </summary>
   4: protected virtual void InitializeCommands()
   5: {
   6:     this.commandProxy   = new GeneralCommandsProxy();
   7:     this.AddNewCommand  = new DelegateCommand<object>(AddNew, CanAddNew);
   8:     this.EditCommand    = new DelegateCommand<object>(Edit, CanEdit);
   9:     this.DeleteCommand  = new DelegateCommand<object>(Delete, CanDelete);
  10:     this.SaveCommand    = new DelegateCommand<object>(Save, CanSave);
  11:     this.DiscardCommand = new DelegateCommand<object>(Discard, CanDiscard);
  12:     this.RefreshCommand = new DelegateCommand<object>(Refresh, CanRefresh);
  13:     this.SearchCommand  = new DelegateCommand<object>(Search, CanSearch);
  14:     this.PrintCommand   = new DelegateCommand<object>(Print, CanPrint);
  15:     this.CloseCommand   = new DelegateCommand<object>(Close, CanClose);
  16: }
  17:  
  18: /// <summary>
  19: /// Registers the commands.
  20: /// </summary>
  21: protected virtual void RegisterCommands()
  22: {
  23:     this.commandProxy.AddNewCommand.RegisterCommand(this.AddNewCommand);
  24:     this.commandProxy.EditCommand.RegisterCommand(this.EditCommand);
  25:     this.commandProxy.DeleteCommand.RegisterCommand(this.DeleteCommand);
  26:     this.commandProxy.SaveCommand.RegisterCommand(this.SaveCommand);
  27:     this.commandProxy.DiscardCommand.RegisterCommand(this.DiscardCommand);
  28:     this.commandProxy.RefreshCommand.RegisterCommand(this.RefreshCommand);
  29:     this.commandProxy.SearchCommand.RegisterCommand(this.SearchCommand);
  30:     this.commandProxy.PrintCommand.RegisterCommand(this.PrintCommand);
  31:     this.commandProxy.CloseCommand.RegisterCommand(this.CloseCommand);
  32: }

Los métodos que se pasan como parámetro del DelegateCommand sirven para ejecutar la acción ligada al comando y indicar si es posible o no su ejecución, para actualizar el estado de ejecución de los comandos la clase dispone de un método más ( que los actualiza todos en bloque aunque también puede ser que en algún momento se necesite hacerlo de forma individual )

   1: private void UpdateAllowedUserActions()
   2: {
   3:     this.AddNewCommand.RaiseCanExecuteChanged();
   4:     this.EditCommand.RaiseCanExecuteChanged();
   5:     this.DeleteCommand.RaiseCanExecuteChanged();
   6:     this.SaveCommand.RaiseCanExecuteChanged();
   7:     this.DiscardCommand.RaiseCanExecuteChanged();
   8:     this.RefreshCommand.RaiseCanExecuteChanged();
   9:     this.SearchCommand.RaiseCanExecuteChanged();
  10:     this.PrintCommand.RaiseCanExecuteChanged();
  11:     this.CloseCommand.RaiseCanExecuteChanged();
  12: }

A modo de ejemplo veamos como están implementados los métodos Refresh y CanRefresh

   1: protected virtual bool CanRefresh(object obj)
   2: {
   3:     return (this.ViewModelState == ViewModelStateType.Default &&
   4:             this.RefreshCommand.IsActive);
   5: }
   6:  
   7: protected virtual void Refresh(object obj)
   8: {
   9:     if (this.RefreshCommand.IsActive)
  10:     {
  11:         if (this.ViewModelState == ViewModelStateType.Default)
  12:         {
  13:             this.ViewModelState = ViewModelStateType.Busy;
  14:  
  15:             if (!ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
  16:                 { 
  17:                     this.OnRefresh(new ServiceResponse<TDataModel>()); 
  18:                 })))
  19:             {
  20:                 this.ViewModelState = ViewModelStateType.Invalid;
  21:             }
  22:         }
  23:     }
  24: }

El comando de Refresh sirve para actualizar los datos en pantalla la acción solo debe estar disponible cuando el estado de la vista sea el estado por defecto ( Consulta ) y que además el comando este activo ( salvo los comandos de Cerrar Todo ( CloseAll ) y Guardar Todo ( SaveAll ) el resto son comandos que sólo deben estar disponibles para la vista activa ( en otro post intentaré explicar como se controla esto ).

El método Refresh comprueba que el comando está activo y el estado actual de la vista, si son correctos ejecuta la acción a realizar de forma asíncrona ( esto también quedará para un post posterior ).

Los métodos para el resto de los comandos están implementados de la misma forma, lo que cambia son las comprobaciones a realizar, por ejemplo el comando de Guardar ( Save ) sólo se debe de poder ejecutar cuando la vista esté en estado de Añadir ( AddingNew ) o Editar ( Editing ), que además haya cambios en los datos y que los datos sean válidos.

   1: protected virtual bool CanSave(object obj)
   2: {
   3:     return (this.ViewModelState == ViewModelStateType.AddingNew ||
   4:             (this.ViewModelState == ViewModelStateType.Editing && this.IsDirty) &&
   5:             this.SaveCommand.IsActive && this.IsValid);
   6: }
08
Jul
08

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 )




calendario

Julio 2008
L M X J V S D
« Jun   Ago »
 123456
78910111213
14151617181920
21222324252627
28293031  

a