1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Collections.ObjectModel; 5 using System.Data.Linq; 6 using System.Linq.Expressions; 7 using System.Reflection; 8 using System.Text; 9 using System.Linq; 10 using System.Diagnostics.CodeAnalysis; 11 12 namespace System.Data.Linq.Mapping { 13 /// <summary> 14 /// A MetaModel is an abstraction representing the mapping between a database and domain objects 15 /// </summary> 16 public abstract class MetaModel { 17 /// <summary> 18 /// The mapping source that originated this model. 19 /// </summary> 20 public abstract MappingSource MappingSource { get; } 21 /// <summary> 22 /// The type of DataContext type this model describes. 23 /// </summary> 24 public abstract Type ContextType { get; } 25 /// <summary> 26 /// The name of the database. 27 /// </summary> 28 public abstract string DatabaseName { get; } 29 /// <summary> 30 /// The CLR type that implements IProvider to use as a provider. 31 /// </summary> 32 public abstract Type ProviderType { get; } 33 /// <summary> 34 /// Gets the MetaTable associated with a given type. 35 /// </summary> 36 /// <param name="rowType">The CLR row type.</param> 37 /// <returns>The MetaTable if one exists, otherwise null.</returns> GetTable(Type rowType)38 public abstract MetaTable GetTable(Type rowType); 39 /// <summary> 40 /// Gets the MetaFunction corresponding to a database function: user-defined function, table-valued function or stored-procedure. 41 /// </summary> 42 /// <param name="method">The method defined on the DataContext or subordinate class that represents the database function.</param> 43 /// <returns>The MetaFunction if one exists, otherwise null.</returns> GetFunction(MethodInfo method)44 public abstract MetaFunction GetFunction(MethodInfo method); 45 /// <summary> 46 /// Get an enumeration of all tables. 47 /// </summary> 48 /// <returns>An enumeration of all the MetaTables</returns> 49 [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Non-trivial operations are not suitable for properties.")] GetTables()50 public abstract IEnumerable<MetaTable> GetTables(); 51 /// <summary> 52 /// Get an enumeration of all functions. 53 /// </summary> 54 /// <returns>An enumeration of all the MetaFunctions</returns> 55 [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Non-trivial operations are not suitable for properties.")] GetFunctions()56 public abstract IEnumerable<MetaFunction> GetFunctions(); 57 /// <summary> 58 /// This method discovers the MetaType for the given Type. 59 /// </summary> GetMetaType(Type type)60 public abstract MetaType GetMetaType(Type type); 61 /// <summary> 62 /// Internal value used to determine a reference identity for comparing meta models 63 /// without needing to keep track of the actual meta model reference. 64 /// </summary> 65 private object identity = new object(); 66 internal object Identity { 67 get { return this.identity; } 68 } 69 } 70 71 /// <summary> 72 /// A MetaTable represents an abstraction of a database table (or view) 73 /// </summary> 74 public abstract class MetaTable { 75 /// <summary> 76 /// The MetaModel containing this MetaTable. 77 /// </summary> 78 public abstract MetaModel Model { get; } 79 /// <summary> 80 /// The name of the table as defined by the database. 81 /// </summary> 82 public abstract string TableName { get; } 83 /// <summary> 84 /// The MetaType describing the type of the rows of the table. 85 /// </summary> 86 public abstract MetaType RowType { get; } 87 /// <summary> 88 /// The DataContext method used to perform insert operations 89 /// </summary> 90 public abstract MethodInfo InsertMethod { get; } 91 /// <summary> 92 /// The DataContext method used to perform update operations 93 /// </summary> 94 public abstract MethodInfo UpdateMethod { get; } 95 /// <summary> 96 /// The DataContext method used to perform delete operations 97 /// </summary> 98 public abstract MethodInfo DeleteMethod { get; } 99 } 100 101 /// <summary> 102 /// A MetaType represents the mapping of a domain object type onto a database table's columns. 103 /// </summary> 104 public abstract class MetaType { 105 /// <summary> 106 /// The MetaModel containing this MetaType. 107 /// </summary> 108 public abstract MetaModel Model { get; } 109 /// <summary> 110 /// The MetaTable using this MetaType for row definition. 111 /// </summary> 112 public abstract MetaTable Table { get; } 113 /// <summary> 114 /// The underlying CLR type. 115 /// </summary> 116 [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The contexts in which this is available are fairly specific.")] 117 public abstract Type Type { get; } 118 /// <summary> 119 /// The name of the MetaType (same as the CLR type's name). 120 /// </summary> 121 public abstract string Name { get; } 122 /// <summary> 123 /// True if the MetaType is an entity type. 124 /// </summary> 125 public abstract bool IsEntity { get; } 126 /// <summary> 127 /// True if the underlying type can be instantiated as the result of a query. 128 /// </summary> 129 public abstract bool CanInstantiate { get; } 130 /// <summary> 131 /// The member that represents the auto-generated identity column, or null if there is none. 132 /// </summary> 133 public abstract MetaDataMember DBGeneratedIdentityMember { get; } 134 /// <summary> 135 /// The member that represents the row-version or timestamp column, or null if there is none. 136 /// </summary> 137 public abstract MetaDataMember VersionMember { get; } 138 /// <summary> 139 /// The member that represents the inheritance discriminator column, or null if there is none. 140 /// </summary> 141 public abstract MetaDataMember Discriminator { get; } 142 /// <summary> 143 /// True if the type has any persistent member with an UpdateCheck policy other than Never. 144 /// </summary> 145 public abstract bool HasUpdateCheck { get; } 146 /// <summary> 147 /// True if the type is part of a mapped inheritance hierarchy. 148 /// </summary> 149 public abstract bool HasInheritance { get; } 150 /// <summary> 151 /// True if this type defines an inheritance code. 152 /// </summary> 153 public abstract bool HasInheritanceCode { get; } 154 /// <summary> 155 /// The inheritance code defined by this type. 156 /// </summary> 157 public abstract object InheritanceCode { get; } 158 /// <summary> 159 /// True if this type is used as the default of an inheritance hierarchy. 160 /// </summary> 161 public abstract bool IsInheritanceDefault { get; } 162 /// <summary> 163 /// The root type of the inheritance hierarchy. 164 /// </summary> 165 public abstract MetaType InheritanceRoot { get; } 166 /// <summary> 167 /// The base metatype in the inheritance hierarchy. 168 /// </summary> 169 public abstract MetaType InheritanceBase { get; } 170 /// <summary> 171 /// The type that is the default of the inheritance hierarchy. 172 /// </summary> 173 public abstract MetaType InheritanceDefault { get; } 174 /// <summary> 175 /// Gets the MetaType for an inheritance sub type. 176 /// </summary> 177 /// <param name="type">The root or sub type of the inheritance hierarchy.</param> 178 /// <returns>The MetaType.</returns> GetInheritanceType(Type type)179 public abstract MetaType GetInheritanceType(Type type); 180 /// <summary> 181 /// Gets type associated with the specified inheritance code. 182 /// </summary> 183 /// <param name="code">The inheritance code</param> 184 /// <returns>The MetaType.</returns> GetTypeForInheritanceCode(object code)185 public abstract MetaType GetTypeForInheritanceCode(object code); 186 /// <summary> 187 /// Gets an enumeration of all types defined by an inheritance hierarchy. 188 /// </summary> 189 /// <returns>Enumeration of MetaTypes.</returns> 190 public abstract ReadOnlyCollection<MetaType> InheritanceTypes { get; } 191 /// <summary> 192 /// Returns true if the MetaType or any base MetaType has an OnLoaded method. 193 /// </summary> 194 public abstract bool HasAnyLoadMethod { get; } 195 /// <summary> 196 /// Returns true if the MetaType or any base MetaType has an OnValidate method. 197 /// </summary> 198 public abstract bool HasAnyValidateMethod { get; } 199 /// <summary> 200 /// Gets an enumeration of the immediate derived types in an inheritance hierarchy. 201 /// </summary> 202 /// <returns>Enumeration of MetaTypes.</returns> 203 public abstract ReadOnlyCollection<MetaType> DerivedTypes { get; } 204 /// <summary> 205 /// Gets an enumeration of all the data members (fields and properties). 206 /// </summary> 207 public abstract ReadOnlyCollection<MetaDataMember> DataMembers { get; } 208 /// <summary> 209 /// Gets an enumeration of all the persistent data members (fields and properties mapped into database columns). 210 /// </summary> 211 public abstract ReadOnlyCollection<MetaDataMember> PersistentDataMembers { get; } 212 /// <summary> 213 /// Gets an enumeration of all the data members that define up the unique identity of the type. 214 /// </summary> 215 public abstract ReadOnlyCollection<MetaDataMember> IdentityMembers { get; } 216 /// <summary> 217 /// Gets an enumeration of all the associations. 218 /// </summary> 219 public abstract ReadOnlyCollection<MetaAssociation> Associations { get; } 220 /// <summary> 221 /// Gets the MetaDataMember associated with the specified member. 222 /// </summary> 223 /// <param name="member">The CLR member.</param> 224 /// <returns>The MetaDataMember if there is one, otherwise null.</returns> GetDataMember(MemberInfo member)225 public abstract MetaDataMember GetDataMember(MemberInfo member); 226 /// <summary> 227 /// The method called when the entity is first loaded. 228 /// </summary> 229 public abstract MethodInfo OnLoadedMethod { get; } 230 /// <summary> 231 /// The method called to ensure the entity is in a valid state. 232 /// </summary> 233 public abstract MethodInfo OnValidateMethod { get; } 234 } 235 236 /// <summary> 237 /// A MetaDataMember represents the mapping between a domain object's field or property into a database table's column. 238 /// </summary> 239 [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "MetaData", Justification = "The capitalization was deliberately chosen.")] 240 public abstract class MetaDataMember { 241 /// <summary> 242 /// The MetaType containing this data member. 243 /// </summary> 244 public abstract MetaType DeclaringType { get; } 245 /// <summary> 246 /// The underlying MemberInfo. 247 /// </summary> 248 public abstract MemberInfo Member { get; } 249 /// <summary> 250 /// The member that actually stores this member's data. 251 /// </summary> 252 public abstract MemberInfo StorageMember { get; } 253 /// <summary> 254 /// The name of the member, same as the MemberInfo name. 255 /// </summary> 256 public abstract string Name { get; } 257 /// <summary> 258 /// The name of the column (or constraint) in the database. 259 /// </summary> 260 public abstract string MappedName { get; } 261 /// <summary> 262 /// The oridinal position of this member in the default layout of query results. 263 /// </summary> 264 public abstract int Ordinal { get; } 265 /// <summary> 266 /// The type of this member. 267 /// </summary> 268 [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The contexts in which this is available are fairly specific.")] 269 public abstract Type Type { get; } 270 /// <summary> 271 /// True if this member is declared by the specified type. 272 /// </summary> 273 /// <param name="type">Type to check.</param> IsDeclaredBy(MetaType type)274 public abstract bool IsDeclaredBy(MetaType type); 275 /// <summary> 276 /// The accessor used to get/set the value of this member. 277 /// </summary> 278 public abstract MetaAccessor MemberAccessor { get; } 279 /// <summary> 280 /// The accessor used to get/set the storage value of this member. 281 /// </summary> 282 public abstract MetaAccessor StorageAccessor { get; } 283 /// <summary> 284 /// The accessor used to get/set the deferred value of this member (without causing fetch). 285 /// </summary> 286 public abstract MetaAccessor DeferredValueAccessor { get; } 287 /// <summary> 288 /// The accessor used to get/set the deferred source of this member. 289 /// </summary> 290 public abstract MetaAccessor DeferredSourceAccessor { get; } 291 /// <summary> 292 /// True if this member is defer-loaded by default. 293 /// </summary> 294 public abstract bool IsDeferred { get; } 295 /// <summary> 296 /// True if this member is mapped to a column (or constraint). 297 /// </summary> 298 public abstract bool IsPersistent { get; } 299 /// <summary> 300 /// True if this member defines an association relationship. 301 /// </summary> 302 public abstract bool IsAssociation { get; } 303 /// <summary> 304 /// True if this member is part of the type's identity. 305 /// </summary> 306 public abstract bool IsPrimaryKey { get; } 307 /// <summary> 308 /// True if this member is automatically generated by the database. 309 /// </summary> 310 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification = "Conforms to legacy spelling.")] 311 public abstract bool IsDbGenerated { get; } 312 /// <summary> 313 /// True if this member represents the row version or timestamp. 314 /// </summary> 315 public abstract bool IsVersion { get; } 316 /// <summary> 317 /// True if this member represents the inheritance discriminator. 318 /// </summary> 319 public abstract bool IsDiscriminator { get; } 320 /// <summary> 321 /// True if this member's value can be assigned the null value. 322 /// </summary> 323 public abstract bool CanBeNull { get; } 324 /// <summary> 325 /// The type of the database column. 326 /// </summary> 327 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification = "Conforms to legacy spelling.")] 328 public abstract string DbType { get; } 329 /// <summary> 330 /// Expression defining a computed column. 331 /// </summary> 332 public abstract string Expression { get; } 333 /// <summary> 334 /// The optimistic concurrency check policy for this member. 335 /// </summary> 336 public abstract UpdateCheck UpdateCheck { get; } 337 /// <summary> 338 /// Specifies for inserts and updates when this member should be read back after the 339 /// operation completes. 340 /// </summary> 341 public abstract AutoSync AutoSync { get; } 342 /// <summary> 343 /// The MetaAssociation corresponding to this member, or null if there is none. 344 /// </summary> 345 public abstract MetaAssociation Association { get; } 346 /// <summary> 347 /// The DataContext method used to perform load operations 348 /// </summary> 349 public abstract MethodInfo LoadMethod { get; } 350 } 351 352 /// <summary> 353 /// A MetaFunction represents the mapping between a context method and a database function. 354 /// </summary> 355 public abstract class MetaFunction { 356 /// <summary> 357 /// The MetaModel containing this function. 358 /// </summary> 359 public abstract MetaModel Model { get; } 360 /// <summary> 361 /// The underlying context method. 362 /// </summary> 363 public abstract MethodInfo Method { get; } 364 /// <summary> 365 /// The name of the method (same as the MethodInfo's name). 366 /// </summary> 367 public abstract string Name { get; } 368 /// <summary> 369 /// The name of the database function or procedure. 370 /// </summary> 371 public abstract string MappedName { get; } 372 /// <summary> 373 /// True if the function can be composed within a query 374 /// </summary> 375 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Composable", Justification="Spelling is correct.")] 376 public abstract bool IsComposable { get; } 377 /// <summary> 378 /// Gets an enumeration of the function parameters. 379 /// </summary> 380 /// <returns></returns> 381 public abstract ReadOnlyCollection<MetaParameter> Parameters { get; } 382 /// <summary> 383 /// The return parameter 384 /// </summary> 385 public abstract MetaParameter ReturnParameter { get; } 386 /// <summary> 387 /// True if the stored procedure has multiple result types. 388 /// </summary> 389 public abstract bool HasMultipleResults { get; } 390 /// <summary> 391 /// An enumeration of all the known result row types of a stored-procedure. 392 /// </summary> 393 /// <returns>Enumeration of possible result row types.</returns> 394 public abstract ReadOnlyCollection<MetaType> ResultRowTypes { get; } 395 } 396 397 /// <summary> 398 /// A MetaParameter represents the mapping between a method parameter and a database function parameter. 399 /// </summary> 400 public abstract class MetaParameter { 401 /// <summary> 402 /// The underlying method parameter. 403 /// </summary> 404 public abstract ParameterInfo Parameter { get; } 405 /// <summary> 406 /// The name of the parameter (same as the ParameterInfo's name). 407 /// </summary> 408 public abstract string Name { get; } 409 /// <summary> 410 /// The name of the database function's parameter. 411 /// </summary> 412 public abstract string MappedName { get; } 413 /// <summary> 414 /// The CLR type of the parameter. 415 /// </summary> 416 public abstract Type ParameterType { get; } 417 /// <summary> 418 /// The database type of the parameter. 419 /// </summary> 420 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification = "Conforms to legacy spelling.")] 421 public abstract string DbType { get; } 422 } 423 424 /// <summary> 425 /// A MetaAssociation represents an association relationship between two entity types. 426 /// </summary> 427 public abstract class MetaAssociation { 428 /// <summary> 429 /// The type on the other end of the association. 430 /// </summary> 431 public abstract MetaType OtherType { get; } 432 /// <summary> 433 /// The member on this side that represents the association. 434 /// </summary> 435 public abstract MetaDataMember ThisMember { get; } 436 /// <summary> 437 /// The member on the other side of this association that represents the reverse association (may be null). 438 /// </summary> 439 public abstract MetaDataMember OtherMember { get; } 440 /// <summary> 441 /// A list of members representing the values on this side of the association. 442 /// </summary> 443 public abstract ReadOnlyCollection<MetaDataMember> ThisKey { get; } 444 /// <summary> 445 /// A list of members representing the values on the other side of the association. 446 /// </summary> 447 public abstract ReadOnlyCollection<MetaDataMember> OtherKey { get; } 448 /// <summary> 449 /// True if the association is OneToMany. 450 /// </summary> 451 public abstract bool IsMany { get; } 452 /// <summary> 453 /// True if the other type is the parent of this type. 454 /// </summary> 455 public abstract bool IsForeignKey { get; } 456 /// <summary> 457 /// True if the association is unique (defines a uniqueness constraint). 458 /// </summary> 459 public abstract bool IsUnique { get; } 460 /// <summary> 461 /// True if the association may be null (key values). 462 /// </summary> 463 public abstract bool IsNullable { get; } 464 /// <summary> 465 /// True if the ThisKey forms the identity (primary key) of the this type. 466 /// </summary> 467 public abstract bool ThisKeyIsPrimaryKey { get; } 468 /// <summary> 469 /// True if the OtherKey forms the identity (primary key) of the other type. 470 /// </summary> 471 public abstract bool OtherKeyIsPrimaryKey { get; } 472 /// <summary> 473 /// Specifies the behavior when the child is deleted (e.g. CASCADE, SET NULL). 474 /// Returns null if no action is specified on delete. 475 /// </summary> 476 public abstract string DeleteRule { get; } 477 /// <summary> 478 /// Specifies whether the object should be deleted when this association 479 /// is set to null. 480 /// </summary> 481 public abstract bool DeleteOnNull { get; } 482 } 483 484 /// <summary> 485 /// A MetaAccessor 486 /// </summary> 487 public abstract class MetaAccessor { 488 /// <summary> 489 /// The type of the member accessed by this accessor. 490 /// </summary> 491 [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The contexts in which this is available are fairly specific.")] 492 public abstract Type Type { get; } 493 /// <summary> 494 /// Gets the value as an object. 495 /// </summary> 496 /// <param name="instance">The instance to get the value from.</param> 497 /// <returns>Value.</returns> GetBoxedValue(object instance)498 public abstract object GetBoxedValue(object instance); 499 /// <summary> 500 /// Sets the value as an object. 501 /// </summary> 502 /// <param name="instance">The instance to set the value into.</param> 503 /// <param name="value">The value to set.</param> 504 [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Microsoft: Needs to handle classes and structs.")] 505 [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification="Unknown reason.")] SetBoxedValue(ref object instance, object value)506 public abstract void SetBoxedValue(ref object instance, object value); 507 /// <summary> 508 /// True if the instance has a loaded or assigned value. 509 /// </summary> HasValue(object instance)510 public virtual bool HasValue(object instance) { 511 return true; 512 } 513 /// <summary> 514 /// True if the instance has an assigned value. 515 /// </summary> HasAssignedValue(object instance)516 public virtual bool HasAssignedValue(object instance) { 517 return true; 518 } 519 /// <summary> 520 /// True if the instance has a value loaded from a deferred source. 521 /// </summary> HasLoadedValue(object instance)522 public virtual bool HasLoadedValue(object instance) { 523 return false; 524 } 525 } 526 527 /// <summary> 528 /// A strongly-typed MetaAccessor. Used for reading from and writing to 529 /// CLR objects. 530 /// </summary> 531 /// <typeparam name="T">The type of the object</typeparam> 532 /// <typeparam name="V">The type of the accessed member</typeparam> 533 public abstract class MetaAccessor<TEntity, TMember> : MetaAccessor { 534 /// <summary> 535 /// The underlying CLR type. 536 /// </summary> 537 public override Type Type { 538 get { return typeof(TMember); } 539 } 540 /// <summary> 541 /// Set the boxed value on an instance. 542 /// </summary> SetBoxedValue(ref object instance, object value)543 public override void SetBoxedValue(ref object instance, object value) { 544 TEntity tInst = (TEntity)instance; 545 this.SetValue(ref tInst, (TMember)value); 546 instance = tInst; 547 } 548 /// <summary> 549 /// Retrieve the boxed value. 550 /// </summary> GetBoxedValue(object instance)551 public override object GetBoxedValue(object instance) { 552 return this.GetValue((TEntity)instance); 553 } 554 /// <summary> 555 /// Gets the strongly-typed value. 556 /// </summary> GetValue(TEntity instance)557 public abstract TMember GetValue(TEntity instance); 558 /// <summary> 559 /// Sets the strongly-typed value 560 /// </summary> 561 [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "0#", Justification = "Unknown reason.")] SetValue(ref TEntity instance, TMember value)562 public abstract void SetValue(ref TEntity instance, TMember value); 563 } 564 } 565