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 )
0 Respuestas a “Data Transfer Object”