AttributedMetaModel.cs 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. using System.Linq.Expressions;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Linq;
  9. using System.Data.Linq.Provider;
  10. using System.Data.Linq.SqlClient;
  11. using System.Threading;
  12. using LinqToSqlShared.Mapping;
  13. using System.Runtime.CompilerServices;
  14. namespace System.Data.Linq.Mapping {
  15. internal static class MethodFinder {
  16. internal static MethodInfo FindMethod(Type type, string name, BindingFlags flags, Type[] argTypes) {
  17. return FindMethod(type, name, flags, argTypes, true);
  18. }
  19. internal static MethodInfo FindMethod(Type type, string name, BindingFlags flags, Type[] argTypes, bool allowInherit) {
  20. for (; type != typeof(object); type = type.BaseType) {
  21. MethodInfo mi = type.GetMethod(name, flags | BindingFlags.DeclaredOnly, null, argTypes, null);
  22. if (mi != null || !allowInherit) {
  23. return mi;
  24. }
  25. }
  26. return null;
  27. }
  28. }
  29. internal static class InheritanceBaseFinder {
  30. internal static MetaType FindBase(MetaType derivedType) {
  31. if (derivedType.Type == typeof(object)) {
  32. return null;
  33. }
  34. var clrType = derivedType.Type; // start
  35. var rootClrType = derivedType.InheritanceRoot.Type; // end
  36. var metaTable = derivedType.Table;
  37. MetaType metaType = null;
  38. while (true) {
  39. if (clrType == typeof(object) || clrType == rootClrType) {
  40. return null;
  41. }
  42. clrType = clrType.BaseType;
  43. metaType = derivedType.InheritanceRoot.GetInheritanceType(clrType);
  44. if (metaType != null) {
  45. return metaType;
  46. }
  47. }
  48. }
  49. }
  50. internal class AttributedMetaModel : MetaModel {
  51. ReaderWriterLock @lock = new ReaderWriterLock();
  52. MappingSource mappingSource;
  53. Type contextType;
  54. Type providerType;
  55. Dictionary<Type, MetaType> metaTypes;
  56. Dictionary<Type, MetaTable> metaTables;
  57. ReadOnlyCollection<MetaTable> staticTables;
  58. Dictionary<MetaPosition, MetaFunction> metaFunctions;
  59. string dbName;
  60. bool initStaticTables;
  61. bool initFunctions;
  62. internal AttributedMetaModel(MappingSource mappingSource, Type contextType) {
  63. this.mappingSource = mappingSource;
  64. this.contextType = contextType;
  65. this.metaTypes = new Dictionary<Type, MetaType>();
  66. this.metaTables = new Dictionary<Type, MetaTable>();
  67. this.metaFunctions = new Dictionary<MetaPosition, MetaFunction>();
  68. // Provider type
  69. ProviderAttribute[] attrs = (ProviderAttribute[])this.contextType.GetCustomAttributes(typeof(ProviderAttribute), true);
  70. if (attrs != null && attrs.Length == 1) { // Provider attribute is !AllowMultiple
  71. this.providerType = attrs[0].Type;
  72. } else {
  73. this.providerType = typeof(SqlProvider);
  74. }
  75. // Database name
  76. DatabaseAttribute[] das = (DatabaseAttribute[])this.contextType.GetCustomAttributes(typeof(DatabaseAttribute), false);
  77. this.dbName = (das != null && das.Length > 0) ? das[0].Name : this.contextType.Name;
  78. }
  79. public override MappingSource MappingSource {
  80. get { return this.mappingSource; }
  81. }
  82. public override Type ContextType {
  83. get { return this.contextType; }
  84. }
  85. public override string DatabaseName {
  86. get { return this.dbName; }
  87. }
  88. public override Type ProviderType {
  89. get { return this.providerType; }
  90. }
  91. public override IEnumerable<MetaTable> GetTables() {
  92. this.InitStaticTables();
  93. if (this.staticTables.Count > 0) {
  94. return this.staticTables;
  95. }
  96. else {
  97. @lock.AcquireReaderLock(Timeout.Infinite);
  98. try {
  99. return this.metaTables.Values.Where(x => x != null).Distinct();
  100. }
  101. finally {
  102. @lock.ReleaseReaderLock();
  103. }
  104. }
  105. }
  106. #region Initialization
  107. private void InitStaticTables() {
  108. if (!this.initStaticTables) {
  109. @lock.AcquireWriterLock(Timeout.Infinite);
  110. try {
  111. if (!this.initStaticTables) {
  112. HashSet<MetaTable> tables = new HashSet<MetaTable>();
  113. for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) {
  114. FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
  115. foreach (FieldInfo fi in fields) {
  116. Type ft = fi.FieldType;
  117. if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Table<>)) {
  118. Type rowType = ft.GetGenericArguments()[0];
  119. tables.Add(this.GetTableNoLocks(rowType));
  120. }
  121. }
  122. PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
  123. foreach (PropertyInfo pi in props) {
  124. Type pt = pi.PropertyType;
  125. if (pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Table<>)) {
  126. Type rowType = pt.GetGenericArguments()[0];
  127. tables.Add(this.GetTableNoLocks(rowType));
  128. }
  129. }
  130. }
  131. this.staticTables = new List<MetaTable>(tables).AsReadOnly();
  132. this.initStaticTables = true;
  133. }
  134. }
  135. finally {
  136. @lock.ReleaseWriterLock();
  137. }
  138. }
  139. }
  140. private void InitFunctions() {
  141. if (!this.initFunctions) {
  142. @lock.AcquireWriterLock(Timeout.Infinite);
  143. try {
  144. if (!this.initFunctions) {
  145. if (this.contextType != typeof(DataContext)) {
  146. for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) {
  147. foreach (MethodInfo mi in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) {
  148. if (IsUserFunction(mi)) {
  149. if (mi.IsGenericMethodDefinition) {
  150. // Added this constraint because XML mapping model didn't support mapping sprocs to generic method.
  151. // The attribute mapping model was, however, able to support it. This check is for parity between
  152. // the two models.
  153. throw Error.InvalidUseOfGenericMethodAsMappedFunction(mi.Name);
  154. }
  155. MetaPosition mp = new MetaPosition(mi);
  156. if (!this.metaFunctions.ContainsKey(mp)) {
  157. MetaFunction metaFunction = new AttributedMetaFunction(this, mi);
  158. this.metaFunctions.Add(mp, metaFunction);
  159. // pre-set all known function result types into metaType map
  160. foreach (MetaType rt in metaFunction.ResultRowTypes) {
  161. foreach (MetaType it in rt.InheritanceTypes) {
  162. if (!this.metaTypes.ContainsKey(it.Type)) {
  163. this.metaTypes.Add(it.Type, it);
  164. }
  165. }
  166. }
  167. }
  168. }
  169. }
  170. }
  171. }
  172. this.initFunctions = true;
  173. }
  174. }
  175. finally {
  176. @lock.ReleaseWriterLock();
  177. }
  178. }
  179. }
  180. private static bool IsUserFunction(MethodInfo mi) {
  181. return Attribute.GetCustomAttribute(mi, typeof(FunctionAttribute), false) != null;
  182. }
  183. #endregion
  184. public override MetaTable GetTable(Type rowType) {
  185. if (rowType == null) {
  186. throw Error.ArgumentNull("rowType");
  187. }
  188. MetaTable table;
  189. @lock.AcquireReaderLock(Timeout.Infinite);
  190. try {
  191. if (this.metaTables.TryGetValue(rowType, out table)) {
  192. return table;
  193. }
  194. }
  195. finally {
  196. @lock.ReleaseReaderLock();
  197. }
  198. @lock.AcquireWriterLock(Timeout.Infinite);
  199. try {
  200. table = this.GetTableNoLocks(rowType);
  201. }
  202. finally {
  203. @lock.ReleaseWriterLock();
  204. }
  205. return table;
  206. }
  207. internal MetaTable GetTableNoLocks(Type rowType) {
  208. MetaTable table;
  209. if (!this.metaTables.TryGetValue(rowType, out table)) {
  210. Type root = GetRoot(rowType) ?? rowType;
  211. TableAttribute[] attrs = (TableAttribute[])root.GetCustomAttributes(typeof(TableAttribute), true);
  212. if (attrs.Length == 0) {
  213. this.metaTables.Add(rowType, null);
  214. }
  215. else {
  216. if (!this.metaTables.TryGetValue(root, out table)) {
  217. table = new AttributedMetaTable(this, attrs[0], root);
  218. foreach (MetaType mt in table.RowType.InheritanceTypes) {
  219. this.metaTables.Add(mt.Type, table);
  220. }
  221. }
  222. // catch case of derived type that is not part of inheritance
  223. if (table.RowType.GetInheritanceType(rowType) == null) {
  224. this.metaTables.Add(rowType, null);
  225. return null;
  226. }
  227. }
  228. }
  229. return table;
  230. }
  231. private static Type GetRoot(Type derivedType) {
  232. while (derivedType != null && derivedType != typeof(object)) {
  233. TableAttribute[] attrs = (TableAttribute[])derivedType.GetCustomAttributes(typeof(TableAttribute), false);
  234. if (attrs.Length > 0)
  235. return derivedType;
  236. derivedType = derivedType.BaseType;
  237. }
  238. return null;
  239. }
  240. public override MetaType GetMetaType(Type type) {
  241. if (type == null) {
  242. throw Error.ArgumentNull("type");
  243. }
  244. MetaType mtype = null;
  245. @lock.AcquireReaderLock(Timeout.Infinite);
  246. try {
  247. if (this.metaTypes.TryGetValue(type, out mtype)) {
  248. return mtype;
  249. }
  250. }
  251. finally {
  252. @lock.ReleaseReaderLock();
  253. }
  254. // Attributed meta model allows us to learn about tables we did not
  255. // statically know about
  256. MetaTable tab = this.GetTable(type);
  257. if (tab != null) {
  258. return tab.RowType.GetInheritanceType(type);
  259. }
  260. this.InitFunctions();
  261. @lock.AcquireWriterLock(Timeout.Infinite);
  262. try {
  263. if (!this.metaTypes.TryGetValue(type, out mtype)) {
  264. mtype = new UnmappedType(this, type);
  265. this.metaTypes.Add(type, mtype);
  266. }
  267. }
  268. finally {
  269. @lock.ReleaseWriterLock();
  270. }
  271. return mtype;
  272. }
  273. public override MetaFunction GetFunction(MethodInfo method) {
  274. if (method == null) {
  275. throw Error.ArgumentNull("method");
  276. }
  277. this.InitFunctions();
  278. MetaFunction function = null;
  279. this.metaFunctions.TryGetValue(new MetaPosition(method), out function);
  280. return function;
  281. }
  282. public override IEnumerable<MetaFunction> GetFunctions() {
  283. this.InitFunctions();
  284. return this.metaFunctions.Values.ToList().AsReadOnly();
  285. }
  286. }
  287. internal sealed class AttributedMetaTable : MetaTable {
  288. AttributedMetaModel model;
  289. string tableName;
  290. MetaType rowType;
  291. bool hasMethods;
  292. MethodInfo insertMethod;
  293. MethodInfo updateMethod;
  294. MethodInfo deleteMethod;
  295. internal AttributedMetaTable(AttributedMetaModel model, TableAttribute attr, Type rowType) {
  296. this.model = model;
  297. this.tableName = string.IsNullOrEmpty(attr.Name) ? rowType.Name : attr.Name;
  298. this.rowType = new AttributedRootType(model, this, rowType);
  299. }
  300. public override MetaModel Model {
  301. get { return this.model; }
  302. }
  303. public override string TableName {
  304. get { return this.tableName; }
  305. }
  306. public override MetaType RowType {
  307. get { return this.rowType; }
  308. }
  309. public override MethodInfo InsertMethod {
  310. get {
  311. this.InitMethods();
  312. return this.insertMethod;
  313. }
  314. }
  315. public override MethodInfo UpdateMethod {
  316. get {
  317. this.InitMethods();
  318. return this.updateMethod;
  319. }
  320. }
  321. public override MethodInfo DeleteMethod {
  322. get {
  323. this.InitMethods();
  324. return this.deleteMethod;
  325. }
  326. }
  327. private void InitMethods() {
  328. if (!this.hasMethods) {
  329. this.insertMethod = MethodFinder.FindMethod(
  330. this.model.ContextType,
  331. "Insert" + rowType.Name,
  332. BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  333. new Type[] { rowType.Type }
  334. );
  335. this.updateMethod = MethodFinder.FindMethod(
  336. this.model.ContextType,
  337. "Update" + rowType.Name,
  338. BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  339. new Type[] { rowType.Type }
  340. );
  341. this.deleteMethod = MethodFinder.FindMethod(
  342. this.model.ContextType,
  343. "Delete" + rowType.Name,
  344. BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  345. new Type[] { rowType.Type }
  346. );
  347. this.hasMethods = true;
  348. }
  349. }
  350. }
  351. internal sealed class AttributedRootType : AttributedMetaType {
  352. Dictionary<Type, MetaType> types;
  353. Dictionary<object, MetaType> codeMap;
  354. ReadOnlyCollection<MetaType> inheritanceTypes;
  355. MetaType inheritanceDefault;
  356. internal AttributedRootType(AttributedMetaModel model, AttributedMetaTable table, Type type)
  357. : base(model, table, type, null) {
  358. // check for inheritance and create all other types
  359. InheritanceMappingAttribute[] inheritanceInfo = (InheritanceMappingAttribute[])type.GetCustomAttributes(typeof(InheritanceMappingAttribute), true);
  360. if (inheritanceInfo.Length > 0) {
  361. if (this.Discriminator == null) {
  362. throw Error.NoDiscriminatorFound(type);
  363. }
  364. if (!MappingSystem.IsSupportedDiscriminatorType(this.Discriminator.Type)) {
  365. throw Error.DiscriminatorClrTypeNotSupported(this.Discriminator.DeclaringType.Name, this.Discriminator.Name, this.Discriminator.Type);
  366. }
  367. this.types = new Dictionary<Type, MetaType>();
  368. this.types.Add(type, this); // add self
  369. this.codeMap = new Dictionary<object, MetaType>();
  370. // initialize inheritance types
  371. foreach (InheritanceMappingAttribute attr in inheritanceInfo) {
  372. if (!type.IsAssignableFrom(attr.Type)) {
  373. throw Error.InheritanceTypeDoesNotDeriveFromRoot(attr.Type, type);
  374. }
  375. if (attr.Type.IsAbstract) {
  376. throw Error.AbstractClassAssignInheritanceDiscriminator(attr.Type);
  377. }
  378. AttributedMetaType mt = this.CreateInheritedType(type, attr.Type);
  379. if (attr.Code == null) {
  380. throw Error.InheritanceCodeMayNotBeNull();
  381. }
  382. if (mt.inheritanceCode != null) {
  383. throw Error.InheritanceTypeHasMultipleDiscriminators(attr.Type);
  384. }
  385. object codeValue = DBConvert.ChangeType(attr.Code, this.Discriminator.Type);
  386. foreach (object d in codeMap.Keys) {
  387. // if the keys are equal, or if they are both strings containing only spaces
  388. // they are considered equal
  389. if ((codeValue.GetType() == typeof(string) && ((string)codeValue).Trim().Length == 0 &&
  390. d.GetType() == typeof(string) && ((string)d).Trim().Length == 0) ||
  391. object.Equals(d, codeValue)) {
  392. throw Error.InheritanceCodeUsedForMultipleTypes(codeValue);
  393. }
  394. }
  395. mt.inheritanceCode = codeValue;
  396. this.codeMap.Add(codeValue, mt);
  397. if (attr.IsDefault) {
  398. if (this.inheritanceDefault != null) {
  399. throw Error.InheritanceTypeHasMultipleDefaults(type);
  400. }
  401. this.inheritanceDefault = mt;
  402. }
  403. }
  404. if (this.inheritanceDefault == null) {
  405. throw Error.InheritanceHierarchyDoesNotDefineDefault(type);
  406. }
  407. }
  408. if (this.types != null) {
  409. this.inheritanceTypes = this.types.Values.ToList().AsReadOnly();
  410. }
  411. else {
  412. this.inheritanceTypes = new MetaType[] { this }.ToList().AsReadOnly();
  413. }
  414. this.Validate();
  415. }
  416. private void Validate() {
  417. Dictionary<object, string> memberToColumn = new Dictionary<object, string>();
  418. foreach (MetaType type in this.InheritanceTypes) {
  419. if (type != this) {
  420. TableAttribute[] attrs = (TableAttribute[])type.Type.GetCustomAttributes(typeof(TableAttribute), false);
  421. if (attrs.Length > 0)
  422. throw Error.InheritanceSubTypeIsAlsoRoot(type.Type);
  423. }
  424. foreach (MetaDataMember mem in type.PersistentDataMembers) {
  425. if (mem.IsDeclaredBy(type)) {
  426. if (mem.IsDiscriminator && !this.HasInheritance) {
  427. throw Error.NonInheritanceClassHasDiscriminator(type);
  428. }
  429. if (!mem.IsAssociation) {
  430. // validate that no database column is mapped twice
  431. if (!string.IsNullOrEmpty(mem.MappedName)) {
  432. string column;
  433. object dn = InheritanceRules.DistinguishedMemberName(mem.Member);
  434. if (memberToColumn.TryGetValue(dn, out column)) {
  435. if (column != mem.MappedName) {
  436. throw Error.MemberMappedMoreThanOnce(mem.Member.Name);
  437. }
  438. }
  439. else {
  440. memberToColumn.Add(dn, mem.MappedName);
  441. }
  442. }
  443. }
  444. }
  445. }
  446. }
  447. }
  448. public override bool HasInheritance {
  449. get { return this.types != null; }
  450. }
  451. private AttributedMetaType CreateInheritedType(Type root, Type type) {
  452. MetaType metaType;
  453. if (!this.types.TryGetValue(type, out metaType)) {
  454. metaType = new AttributedMetaType(this.Model, this.Table, type, this);
  455. this.types.Add(type, metaType);
  456. if (type != root && type.BaseType != typeof(object)) {
  457. this.CreateInheritedType(root, type.BaseType);
  458. }
  459. }
  460. return (AttributedMetaType)metaType;
  461. }
  462. public override ReadOnlyCollection<MetaType> InheritanceTypes {
  463. get { return this.inheritanceTypes; }
  464. }
  465. public override MetaType GetInheritanceType(Type type) {
  466. if (type == this.Type)
  467. return this;
  468. MetaType metaType = null;
  469. if (this.types != null) {
  470. this.types.TryGetValue(type, out metaType);
  471. }
  472. return metaType;
  473. }
  474. public override MetaType InheritanceDefault {
  475. get { return this.inheritanceDefault; }
  476. }
  477. }
  478. internal class AttributedMetaType : MetaType {
  479. MetaModel model;
  480. MetaTable table;
  481. Type type;
  482. Dictionary<MetaPosition, MetaDataMember> dataMemberMap;
  483. ReadOnlyCollection<MetaDataMember> dataMembers;
  484. ReadOnlyCollection<MetaDataMember> persistentMembers;
  485. ReadOnlyCollection<MetaDataMember> identities;
  486. MetaDataMember dbGeneratedIdentity;
  487. MetaDataMember version;
  488. MetaDataMember discriminator;
  489. MetaType inheritanceRoot;
  490. bool inheritanceBaseSet;
  491. MetaType inheritanceBase;
  492. internal object inheritanceCode;
  493. ReadOnlyCollection<MetaType> derivedTypes;
  494. ReadOnlyCollection<MetaAssociation> associations;
  495. bool hasMethods;
  496. bool hasAnyLoadMethod;
  497. bool hasAnyValidateMethod;
  498. MethodInfo onLoadedMethod;
  499. MethodInfo onValidateMethod;
  500. object locktarget = new object(); // Hold locks on private object rather than public MetaType.
  501. internal AttributedMetaType(MetaModel model, MetaTable table, Type type, MetaType inheritanceRoot) {
  502. this.model = model;
  503. this.table = table;
  504. this.type = type;
  505. this.inheritanceRoot = (inheritanceRoot != null) ? inheritanceRoot : this;
  506. // Not lazy-loading to simplify locking and enhance performance
  507. // (because no lock will be required for the common read scenario).
  508. this.InitDataMembers();
  509. this.identities = this.dataMembers.Where(m => m.IsPrimaryKey).ToList().AsReadOnly();
  510. this.persistentMembers = this.dataMembers.Where(m => m.IsPersistent).ToList().AsReadOnly();
  511. }
  512. #region Initialization
  513. private void ValidatePrimaryKeyMember(MetaDataMember mm) {
  514. //if the type is a sub-type, no member declared in the type can be primary key
  515. if (mm.IsPrimaryKey && this.inheritanceRoot != this && mm.Member.DeclaringType == this.type) {
  516. throw(Error.PrimaryKeyInSubTypeNotSupported(this.type.Name, mm.Name));
  517. }
  518. }
  519. private void InitMethods() {
  520. if (!this.hasMethods) {
  521. this.onLoadedMethod = MethodFinder.FindMethod(
  522. this.Type,
  523. "OnLoaded",
  524. BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  525. Type.EmptyTypes,
  526. false
  527. );
  528. this.onValidateMethod = MethodFinder.FindMethod(
  529. this.Type,
  530. "OnValidate",
  531. BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  532. new[] { typeof(ChangeAction) },
  533. false
  534. );
  535. this.hasAnyLoadMethod = (this.onLoadedMethod != null) || (this.InheritanceBase != null && this.InheritanceBase.HasAnyLoadMethod);
  536. this.hasAnyValidateMethod = (this.onValidateMethod != null) || (this.InheritanceBase != null && this.InheritanceBase.HasAnyValidateMethod);
  537. this.hasMethods = true;
  538. }
  539. }
  540. private void InitDataMembers() {
  541. if (this.dataMembers == null) {
  542. this.dataMemberMap = new Dictionary<MetaPosition, MetaDataMember>();
  543. int ordinal = 0;
  544. BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
  545. FieldInfo[] fis = TypeSystem.GetAllFields(this.type, flags).ToArray();
  546. if (fis != null) {
  547. for (int i = 0, n = fis.Length; i < n; i++) {
  548. FieldInfo fi = fis[i];
  549. MetaDataMember mm = new AttributedMetaDataMember(this, fi, ordinal);
  550. ValidatePrimaryKeyMember(mm);
  551. // must be public or persistent
  552. if (!mm.IsPersistent && !fi.IsPublic)
  553. continue;
  554. this.dataMemberMap.Add(new MetaPosition(fi), mm);
  555. ordinal++;
  556. // must be persistent for the rest
  557. if (!mm.IsPersistent)
  558. continue;
  559. this.InitSpecialMember(mm);
  560. }
  561. }
  562. PropertyInfo[] pis = TypeSystem.GetAllProperties(this.type, flags).ToArray();
  563. if (pis != null) {
  564. for (int i = 0, n = pis.Length; i < n; i++) {
  565. PropertyInfo pi = pis[i];
  566. MetaDataMember mm = new AttributedMetaDataMember(this, pi, ordinal);
  567. ValidatePrimaryKeyMember(mm);
  568. // must be public or persistent
  569. bool isPublic = (pi.CanRead && pi.GetGetMethod(false) != null)
  570. && (!pi.CanWrite || pi.GetSetMethod(false) != null);
  571. if (!mm.IsPersistent && !isPublic)
  572. continue;
  573. this.dataMemberMap.Add(new MetaPosition(pi), mm);
  574. ordinal++;
  575. // must be persistent for the rest
  576. if (!mm.IsPersistent)
  577. continue;
  578. this.InitSpecialMember(mm);
  579. }
  580. }
  581. this.dataMembers = new List<MetaDataMember>(this.dataMemberMap.Values).AsReadOnly();
  582. }
  583. }
  584. private void InitSpecialMember(MetaDataMember mm) {
  585. // Can only have one auto gen member that is also an identity member,
  586. // except if that member is a computed column (since they are implicitly auto gen)
  587. if (mm.IsDbGenerated && mm.IsPrimaryKey && string.IsNullOrEmpty(mm.Expression)) {
  588. if (this.dbGeneratedIdentity != null)
  589. throw Error.TwoMembersMarkedAsPrimaryKeyAndDBGenerated(mm.Member, this.dbGeneratedIdentity.Member);
  590. this.dbGeneratedIdentity = mm;
  591. }
  592. if (mm.IsPrimaryKey && !MappingSystem.IsSupportedIdentityType(mm.Type))
  593. {
  594. throw Error.IdentityClrTypeNotSupported(mm.DeclaringType, mm.Name, mm.Type);
  595. }
  596. if (mm.IsVersion) {
  597. if (this.version != null)
  598. throw Error.TwoMembersMarkedAsRowVersion(mm.Member, this.version.Member);
  599. this.version = mm;
  600. }
  601. if (mm.IsDiscriminator) {
  602. if (this.discriminator!=null)
  603. throw Error.TwoMembersMarkedAsInheritanceDiscriminator(mm.Member, this.discriminator.Member);
  604. this.discriminator = mm;
  605. }
  606. }
  607. #endregion
  608. public override MetaModel Model {
  609. get { return this.model; }
  610. }
  611. public override MetaTable Table {
  612. get { return this.table; }
  613. }
  614. public override Type Type {
  615. get { return this.type; }
  616. }
  617. public override string Name {
  618. get { return this.type.Name; }
  619. }
  620. public override bool IsEntity {
  621. get {
  622. if (this.table != null) {
  623. return table.RowType.IdentityMembers.Count > 0;
  624. }
  625. return false;
  626. }
  627. }
  628. public override bool CanInstantiate {
  629. get { return !this.type.IsAbstract && (this == this.InheritanceRoot || this.HasInheritanceCode); }
  630. }
  631. public override MetaDataMember DBGeneratedIdentityMember {
  632. get { return this.dbGeneratedIdentity; }
  633. }
  634. public override MetaDataMember VersionMember {
  635. get { return this.version; }
  636. }
  637. public override MetaDataMember Discriminator {
  638. get { return this.discriminator; }
  639. }
  640. public override bool HasUpdateCheck {
  641. get {
  642. foreach(MetaDataMember member in this.PersistentDataMembers) {
  643. if (member.UpdateCheck != UpdateCheck.Never) {
  644. return true;
  645. }
  646. }
  647. return false;
  648. }
  649. }
  650. public override bool HasInheritance {
  651. get { return this.inheritanceRoot.HasInheritance; }
  652. }
  653. public override bool HasInheritanceCode {
  654. get { return this.inheritanceCode != null; }
  655. }
  656. public override object InheritanceCode {
  657. get { return this.inheritanceCode; }
  658. }
  659. public override MetaType InheritanceRoot {
  660. get { return this.inheritanceRoot; }
  661. }
  662. public override MetaType InheritanceBase {
  663. get {
  664. // LOCKING: Cannot initialize at construction
  665. if (!this.inheritanceBaseSet && this.inheritanceBase == null) {
  666. lock (this.locktarget) {
  667. if (this.inheritanceBase == null) {
  668. this.inheritanceBase = InheritanceBaseFinder.FindBase(this);
  669. this.inheritanceBaseSet = true;
  670. }
  671. }
  672. }
  673. return this.inheritanceBase;
  674. }
  675. }
  676. public override MetaType InheritanceDefault {
  677. get { return this.InheritanceRoot.InheritanceDefault; }
  678. }
  679. public override bool IsInheritanceDefault {
  680. get { return this.InheritanceDefault == this; }
  681. }
  682. public override ReadOnlyCollection<MetaType> InheritanceTypes {
  683. get { return this.inheritanceRoot.InheritanceTypes; }
  684. }
  685. public override MetaType GetInheritanceType(Type inheritanceType) {
  686. if (inheritanceType == this.type)
  687. return this;
  688. return this.inheritanceRoot.GetInheritanceType(inheritanceType);
  689. }
  690. public override ReadOnlyCollection<MetaType> DerivedTypes {
  691. get {
  692. // LOCKING: Cannot initialize at construction because derived types
  693. // won't exist yet.
  694. if (this.derivedTypes == null) {
  695. lock (this.locktarget) {
  696. if (this.derivedTypes == null) {
  697. List<MetaType> dTypes = new List<MetaType>();
  698. foreach (MetaType mt in this.InheritanceTypes) {
  699. if (mt.Type.BaseType == this.type)
  700. dTypes.Add(mt);
  701. }
  702. this.derivedTypes = dTypes.AsReadOnly();
  703. }
  704. }
  705. }
  706. return this.derivedTypes;
  707. }
  708. }
  709. public override MetaType GetTypeForInheritanceCode(object key) {
  710. if (this.InheritanceRoot.Discriminator.Type == typeof(string)) {
  711. string skey = (string)key;
  712. foreach (MetaType mt in this.InheritanceRoot.InheritanceTypes) {
  713. if (string.Compare((string)mt.InheritanceCode, skey, StringComparison.OrdinalIgnoreCase) == 0)
  714. return mt;
  715. }
  716. }
  717. else {
  718. foreach (MetaType mt in this.InheritanceRoot.InheritanceTypes) {
  719. if (object.Equals(mt.InheritanceCode, key))
  720. return mt;
  721. }
  722. }
  723. return null;
  724. }
  725. public override ReadOnlyCollection<MetaDataMember> DataMembers {
  726. get { return this.dataMembers; }
  727. }
  728. public override ReadOnlyCollection<MetaDataMember> PersistentDataMembers {
  729. get { return this.persistentMembers; }
  730. }
  731. public override ReadOnlyCollection<MetaDataMember> IdentityMembers {
  732. get { return this.identities; }
  733. }
  734. public override ReadOnlyCollection<MetaAssociation> Associations {
  735. get {
  736. // LOCKING: Associations are late-expanded so that cycles are broken.
  737. if (this.associations == null) {
  738. lock (this.locktarget) {
  739. if (this.associations == null) {
  740. this.associations = this.dataMembers.Where(m => m.IsAssociation).Select(m => m.Association).ToList().AsReadOnly();
  741. }
  742. }
  743. }
  744. return this.associations;
  745. }
  746. }
  747. public override MetaDataMember GetDataMember(MemberInfo mi) {
  748. if (mi == null)
  749. throw Error.ArgumentNull("mi");
  750. MetaDataMember mm = null;
  751. if (this.dataMemberMap.TryGetValue(new MetaPosition(mi), out mm)) {
  752. return mm;
  753. }
  754. else {
  755. // DON'T look to see if we are trying to get a member from an inherited type.
  756. // The calling code should know to look in the inherited type.
  757. if (mi.DeclaringType.IsInterface) {
  758. throw Error.MappingOfInterfacesMemberIsNotSupported(mi.DeclaringType.Name, mi.Name);
  759. } else { //the member is not mapped in the base class
  760. throw Error.UnmappedClassMember(mi.DeclaringType.Name, mi.Name);
  761. }
  762. }
  763. }
  764. public override MethodInfo OnLoadedMethod {
  765. get {
  766. this.InitMethods();
  767. return this.onLoadedMethod;
  768. }
  769. }
  770. public override MethodInfo OnValidateMethod {
  771. get {
  772. this.InitMethods();
  773. return this.onValidateMethod;
  774. }
  775. }
  776. public override bool HasAnyValidateMethod {
  777. get {
  778. this.InitMethods();
  779. return this.hasAnyValidateMethod;
  780. }
  781. }
  782. public override bool HasAnyLoadMethod {
  783. get {
  784. this.InitMethods();
  785. return this.hasAnyLoadMethod;
  786. }
  787. }
  788. public override string ToString() {
  789. return this.Name;
  790. }
  791. }
  792. internal sealed class AttributedMetaFunction : MetaFunction {
  793. private AttributedMetaModel model;
  794. private MethodInfo methodInfo;
  795. private FunctionAttribute functionAttrib;
  796. private MetaParameter returnParameter;
  797. private ReadOnlyCollection<MetaParameter> parameters;
  798. private ReadOnlyCollection<MetaType> rowTypes;
  799. static ReadOnlyCollection<MetaParameter> _emptyParameters = new List<MetaParameter>(0).AsReadOnly();
  800. static ReadOnlyCollection<MetaType> _emptyTypes = new List<MetaType>(0).AsReadOnly();
  801. /// <summary>
  802. /// Constructor.
  803. /// </summary>
  804. /// <param name="metaType">The parent meta type.</param>
  805. /// <param name="mi">The method info.</param>
  806. public AttributedMetaFunction(AttributedMetaModel model, MethodInfo mi) {
  807. this.model = model;
  808. this.methodInfo = mi;
  809. this.rowTypes = _emptyTypes;
  810. this.functionAttrib = Attribute.GetCustomAttribute(mi, typeof(FunctionAttribute), false) as FunctionAttribute;
  811. System.Diagnostics.Debug.Assert(functionAttrib != null);
  812. // Gather up all mapped results
  813. ResultTypeAttribute[] attrs = (ResultTypeAttribute[])Attribute.GetCustomAttributes(mi, typeof(ResultTypeAttribute));
  814. if (attrs.Length == 0 && mi.ReturnType == typeof(IMultipleResults)) {
  815. throw Error.NoResultTypesDeclaredForFunction(mi.Name);
  816. }
  817. else if (attrs.Length > 1 && mi.ReturnType != typeof(IMultipleResults)) {
  818. throw Error.TooManyResultTypesDeclaredForFunction(mi.Name);
  819. }
  820. else if (attrs.Length <= 1 && mi.ReturnType.IsGenericType &&
  821. (mi.ReturnType.GetGenericTypeDefinition() == typeof(IEnumerable<>) ||
  822. mi.ReturnType.GetGenericTypeDefinition() == typeof(ISingleResult<>) ||
  823. mi.ReturnType.GetGenericTypeDefinition() == typeof(IQueryable<>))) {
  824. Type elementType = TypeSystem.GetElementType(mi.ReturnType);
  825. this.rowTypes = new List<MetaType>(1) { this.GetMetaType(elementType) }.AsReadOnly();
  826. }
  827. else if (attrs.Length > 0) {
  828. List<MetaType> rowTypes = new List<MetaType>();
  829. foreach (ResultTypeAttribute rat in attrs) {
  830. Type type = rat.Type;
  831. MetaType mt = this.GetMetaType(type);
  832. // Only add unique meta types
  833. if (!rowTypes.Contains(mt)) {
  834. rowTypes.Add(mt);
  835. }
  836. }
  837. this.rowTypes = rowTypes.AsReadOnly();
  838. }
  839. else {
  840. this.returnParameter = new AttributedMetaParameter(this.methodInfo.ReturnParameter);
  841. }
  842. // gather up all meta parameter
  843. ParameterInfo[] pis = mi.GetParameters();
  844. if (pis.Length > 0) {
  845. List<MetaParameter> mps = new List<MetaParameter>(pis.Length);
  846. for (int i = 0, n = pis.Length; i < n; i++) {
  847. AttributedMetaParameter metaParam = new AttributedMetaParameter(pis[i]);
  848. mps.Add(metaParam);
  849. }
  850. this.parameters = mps.AsReadOnly();
  851. }
  852. else {
  853. this.parameters = _emptyParameters;
  854. }
  855. }
  856. /// <summary>
  857. /// For the specified type, if it is a mapped type, use the Table
  858. /// metatype to get the correct inheritance metatype,
  859. /// otherwise create a new meta type.
  860. /// </summary>
  861. private MetaType GetMetaType(Type type) {
  862. // call no-lock version of GetTable since this function is called only in constructor
  863. // and constructor is only called by function that already has a lock.
  864. MetaTable tbl = model.GetTableNoLocks(type);
  865. if (tbl != null) {
  866. return tbl.RowType.GetInheritanceType(type);
  867. }
  868. return new AttributedRootType(model, null, type);
  869. }
  870. public override MetaModel Model {
  871. get { return this.model; }
  872. }
  873. public override MethodInfo Method {
  874. get { return this.methodInfo; }
  875. }
  876. public override string Name {
  877. get { return this.methodInfo.Name; }
  878. }
  879. public override string MappedName {
  880. get {
  881. if (!string.IsNullOrEmpty(this.functionAttrib.Name)) {
  882. return this.functionAttrib.Name;
  883. }
  884. return this.methodInfo.Name;
  885. }
  886. }
  887. public override bool IsComposable {
  888. get { return this.functionAttrib.IsComposable; }
  889. }
  890. public override ReadOnlyCollection<MetaParameter> Parameters {
  891. get { return this.parameters; }
  892. }
  893. public override MetaParameter ReturnParameter {
  894. get { return this.returnParameter; }
  895. }
  896. public override bool HasMultipleResults {
  897. get { return this.methodInfo.ReturnType == typeof(IMultipleResults); }
  898. }
  899. public override ReadOnlyCollection<MetaType> ResultRowTypes {
  900. get { return this.rowTypes; }
  901. }
  902. }
  903. internal sealed class AttributedMetaParameter : MetaParameter {
  904. private ParameterInfo parameterInfo;
  905. private ParameterAttribute paramAttrib;
  906. public AttributedMetaParameter(ParameterInfo parameterInfo) {
  907. this.parameterInfo = parameterInfo;
  908. this.paramAttrib = Attribute.GetCustomAttribute(parameterInfo, typeof(ParameterAttribute), false) as ParameterAttribute;
  909. }
  910. public override ParameterInfo Parameter {
  911. get { return this.parameterInfo; }
  912. }
  913. public override string Name {
  914. get { return this.parameterInfo.Name; }
  915. }
  916. public override string MappedName {
  917. get {
  918. if (this.paramAttrib != null && this.paramAttrib.Name != null)
  919. return this.paramAttrib.Name;
  920. return this.parameterInfo.Name;
  921. }
  922. }
  923. public override Type ParameterType {
  924. get { return this.parameterInfo.ParameterType; }
  925. }
  926. public override string DbType {
  927. get {
  928. if (this.paramAttrib != null && this.paramAttrib.DbType != null)
  929. return this.paramAttrib.DbType;
  930. return null;
  931. }
  932. }
  933. }
  934. internal sealed class AttributedMetaDataMember : MetaDataMember {
  935. AttributedMetaType metaType;
  936. MemberInfo member;
  937. MemberInfo storageMember;
  938. int ordinal;
  939. Type type;
  940. Type declaringType;
  941. bool hasAccessors;
  942. MetaAccessor accPublic;
  943. MetaAccessor accPrivate;
  944. MetaAccessor accDefValue;
  945. MetaAccessor accDefSource;
  946. DataAttribute attr;
  947. ColumnAttribute attrColumn;
  948. AssociationAttribute attrAssoc;
  949. AttributedMetaAssociation assoc;
  950. bool isNullableType;
  951. bool isDeferred;
  952. object locktarget = new object(); // Hold locks on private object rather than public MetaType.
  953. bool hasLoadMethod;
  954. MethodInfo loadMethod;
  955. internal AttributedMetaDataMember(AttributedMetaType metaType, MemberInfo mi, int ordinal) {
  956. this.declaringType = mi.DeclaringType;
  957. this.metaType = metaType;
  958. this.member = mi;
  959. this.ordinal = ordinal;
  960. this.type = TypeSystem.GetMemberType(mi);
  961. this.isNullableType = TypeSystem.IsNullableType(this.type);
  962. this.attrColumn = (ColumnAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnAttribute));
  963. this.attrAssoc = (AssociationAttribute)Attribute.GetCustomAttribute(mi, typeof(AssociationAttribute));
  964. this.attr = (this.attrColumn != null) ? (DataAttribute)this.attrColumn : (DataAttribute)this.attrAssoc;
  965. if (this.attr != null && this.attr.Storage != null) {
  966. MemberInfo[] mis = mi.DeclaringType.GetMember(this.attr.Storage, BindingFlags.Instance | BindingFlags.NonPublic);
  967. if (mis == null || mis.Length != 1) {
  968. throw Error.BadStorageProperty(this.attr.Storage, mi.DeclaringType, mi.Name);
  969. }
  970. this.storageMember = mis[0];
  971. }
  972. Type storageType = this.storageMember != null ? TypeSystem.GetMemberType(this.storageMember) : this.type;
  973. this.isDeferred = IsDeferredType(storageType);
  974. if (attrColumn != null && attrColumn.IsDbGenerated && attrColumn.IsPrimaryKey) {
  975. // auto-gen identities must be synced on insert
  976. if ((attrColumn.AutoSync != AutoSync.Default) && (attrColumn.AutoSync != AutoSync.OnInsert)) {
  977. throw Error.IncorrectAutoSyncSpecification(mi.Name);
  978. }
  979. }
  980. }
  981. private void InitAccessors() {
  982. if (!this.hasAccessors) {
  983. lock (this.locktarget) {
  984. if (!this.hasAccessors) {
  985. if (this.storageMember != null) {
  986. this.accPrivate = MakeMemberAccessor(this.member.ReflectedType, this.storageMember, null);
  987. if (this.isDeferred) {
  988. MakeDeferredAccessors(this.member.ReflectedType, this.accPrivate, out this.accPrivate, out this.accDefValue, out this.accDefSource);
  989. }
  990. this.accPublic = MakeMemberAccessor(this.member.ReflectedType, this.member, this.accPrivate);
  991. }
  992. else {
  993. this.accPublic = this.accPrivate = MakeMemberAccessor(this.member.ReflectedType, this.member, null);
  994. if (this.isDeferred) {
  995. MakeDeferredAccessors(this.member.ReflectedType, this.accPrivate, out this.accPrivate, out this.accDefValue, out this.accDefSource);
  996. }
  997. }
  998. this.hasAccessors = true;
  999. }
  1000. }
  1001. }
  1002. }
  1003. public override MetaType DeclaringType {
  1004. get { return this.metaType; }
  1005. }
  1006. public override bool IsDeclaredBy(MetaType declaringMetaType) {
  1007. if (declaringMetaType == null) {
  1008. throw Error.ArgumentNull("declaringMetaType");
  1009. }
  1010. return declaringMetaType.Type == this.declaringType;
  1011. }
  1012. public override MemberInfo Member {
  1013. get { return this.member; }
  1014. }
  1015. public override MemberInfo StorageMember {
  1016. get { return this.storageMember; }
  1017. }
  1018. public override string Name {
  1019. get { return this.member.Name; }
  1020. }
  1021. public override int Ordinal {
  1022. get { return this.ordinal; }
  1023. }
  1024. public override Type Type {
  1025. get { return this.type; }
  1026. }
  1027. public override MetaAccessor MemberAccessor {
  1028. get {
  1029. this.InitAccessors();
  1030. return this.accPublic;
  1031. }
  1032. }
  1033. public override MetaAccessor StorageAccessor {
  1034. get {
  1035. this.InitAccessors();
  1036. return this.accPrivate;
  1037. }
  1038. }
  1039. public override MetaAccessor DeferredValueAccessor {
  1040. get {
  1041. this.InitAccessors();
  1042. return this.accDefValue;
  1043. }
  1044. }
  1045. public override MetaAccessor DeferredSourceAccessor {
  1046. get {
  1047. this.InitAccessors();
  1048. return this.accDefSource;
  1049. }
  1050. }
  1051. public override bool IsDeferred {
  1052. get { return this.isDeferred; }
  1053. }
  1054. public override bool IsPersistent {
  1055. get { return this.attrColumn != null || this.attrAssoc != null; }
  1056. }
  1057. public override bool IsAssociation {
  1058. get { return this.attrAssoc != null; }
  1059. }
  1060. public override bool IsPrimaryKey {
  1061. get { return this.attrColumn != null && this.attrColumn.IsPrimaryKey; }
  1062. }
  1063. /// <summary>
  1064. /// Returns true if the member is explicitly marked as auto gen, or if the
  1065. /// member is computed or generated by the database server.
  1066. /// </summary>
  1067. public override bool IsDbGenerated {
  1068. get {
  1069. return this.attrColumn != null &&
  1070. (this.attrColumn.IsDbGenerated || !string.IsNullOrEmpty(attrColumn.Expression)) || IsVersion;
  1071. }
  1072. }
  1073. public override bool IsVersion {
  1074. get { return this.attrColumn != null && this.attrColumn.IsVersion; }
  1075. }
  1076. public override bool IsDiscriminator {
  1077. get { return attrColumn == null ? false : attrColumn.IsDiscriminator; }
  1078. }
  1079. public override bool CanBeNull {
  1080. get {
  1081. if (this.attrColumn == null) {
  1082. return true;
  1083. }
  1084. if (!this.attrColumn.CanBeNullSet) {
  1085. return this.isNullableType || !this.type.IsValueType;
  1086. }
  1087. return this.attrColumn.CanBeNull;
  1088. }
  1089. }
  1090. public override string DbType {
  1091. get {
  1092. if (this.attrColumn != null) {
  1093. return this.attrColumn.DbType;
  1094. }
  1095. return null;
  1096. }
  1097. }
  1098. public override string Expression {
  1099. get {
  1100. if (this.attrColumn != null) {
  1101. return this.attrColumn.Expression;
  1102. }
  1103. return null;
  1104. }
  1105. }
  1106. public override string MappedName {
  1107. get {
  1108. if (this.attrColumn != null && this.attrColumn.Name != null) {
  1109. return this.attrColumn.Name;
  1110. }
  1111. if (this.attrAssoc != null && this.attrAssoc.Name != null) {
  1112. return this.attrAssoc.Name;
  1113. }
  1114. return this.member.Name;
  1115. }
  1116. }
  1117. public override UpdateCheck UpdateCheck {
  1118. get {
  1119. if (this.attrColumn != null) {
  1120. return this.attrColumn.UpdateCheck;
  1121. }
  1122. return UpdateCheck.Never;
  1123. }
  1124. }
  1125. public override AutoSync AutoSync {
  1126. get {
  1127. if (this.attrColumn != null) {
  1128. // auto-gen keys are always and only synced on insert
  1129. if (this.IsDbGenerated && this.IsPrimaryKey) {
  1130. return AutoSync.OnInsert;
  1131. }
  1132. // if the user has explicitly set it, use their value
  1133. if (attrColumn.AutoSync != AutoSync.Default) {
  1134. return attrColumn.AutoSync;
  1135. }
  1136. // database generated members default to always
  1137. if (this.IsDbGenerated) {
  1138. return AutoSync.Always;
  1139. }
  1140. }
  1141. return AutoSync.Never;
  1142. }
  1143. }
  1144. public override MetaAssociation Association {
  1145. get {
  1146. if (this.IsAssociation) {
  1147. // LOCKING: This deferral isn't an optimization. It can't be done in the constructor
  1148. // because there may be loops in the association graph.
  1149. if (this.assoc == null) {
  1150. lock (this.locktarget) {
  1151. if (this.assoc == null) {
  1152. this.assoc = new AttributedMetaAssociation(this, this.attrAssoc);
  1153. }
  1154. }
  1155. }
  1156. }
  1157. return this.assoc;
  1158. }
  1159. }
  1160. public override MethodInfo LoadMethod {
  1161. get {
  1162. if (this.hasLoadMethod == false && (this.IsDeferred || this.IsAssociation)) {
  1163. // defer searching for this access method until we really need to know
  1164. this.loadMethod = MethodFinder.FindMethod(
  1165. ((AttributedMetaModel)this.metaType.Model).ContextType,
  1166. "Load" + this.member.Name,
  1167. BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  1168. new Type[] { this.DeclaringType.Type }
  1169. );
  1170. this.hasLoadMethod = true;
  1171. }
  1172. return this.loadMethod;
  1173. }
  1174. }
  1175. private bool IsDeferredType(Type entityType) {
  1176. if (entityType == null || entityType == typeof(object)) {
  1177. return false;
  1178. }
  1179. if (entityType.IsGenericType) {
  1180. Type gtype = entityType.GetGenericTypeDefinition();
  1181. return gtype == typeof(Link<>) ||
  1182. typeof(EntitySet<>).IsAssignableFrom(gtype) ||
  1183. typeof(EntityRef<>).IsAssignableFrom(gtype) ||
  1184. IsDeferredType(entityType.BaseType);
  1185. }
  1186. return false;
  1187. }
  1188. private static MetaAccessor MakeMemberAccessor(Type accessorType, MemberInfo mi, MetaAccessor storage) {
  1189. FieldInfo fi = mi as FieldInfo;
  1190. MetaAccessor acc = null;
  1191. if (fi != null) {
  1192. acc = FieldAccessor.Create(accessorType, fi);
  1193. }
  1194. else {
  1195. PropertyInfo pi = (PropertyInfo)mi;
  1196. acc = PropertyAccessor.Create(accessorType, pi, storage);
  1197. }
  1198. return acc;
  1199. }
  1200. [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
  1201. private static void MakeDeferredAccessors(
  1202. Type objectDeclaringType, MetaAccessor accessor,
  1203. out MetaAccessor accessorValue, out MetaAccessor accessorDeferredValue, out MetaAccessor accessorDeferredSource
  1204. ) {
  1205. if (accessor.Type.IsGenericType) {
  1206. Type gtype = accessor.Type.GetGenericTypeDefinition();
  1207. Type itemType = accessor.Type.GetGenericArguments()[0];
  1208. if (gtype == typeof(Link<>)) {
  1209. accessorValue = CreateAccessor(typeof(LinkValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1210. accessorDeferredValue = CreateAccessor(typeof(LinkDefValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1211. accessorDeferredSource = CreateAccessor(typeof(LinkDefSourceAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1212. return;
  1213. }
  1214. else if (typeof(EntityRef<>).IsAssignableFrom(gtype)) {
  1215. accessorValue = CreateAccessor(typeof(EntityRefValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1216. accessorDeferredValue = CreateAccessor(typeof(EntityRefDefValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1217. accessorDeferredSource = CreateAccessor(typeof(EntityRefDefSourceAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1218. return;
  1219. }
  1220. else if (typeof(EntitySet<>).IsAssignableFrom(gtype)) {
  1221. accessorValue = CreateAccessor(typeof(EntitySetValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1222. accessorDeferredValue = CreateAccessor(typeof(EntitySetDefValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1223. accessorDeferredSource = CreateAccessor(typeof(EntitySetDefSourceAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
  1224. return;
  1225. }
  1226. }
  1227. throw Error.UnhandledDeferredStorageType(accessor.Type);
  1228. }
  1229. private static MetaAccessor CreateAccessor(Type accessorType, params object[] args) {
  1230. return (MetaAccessor)Activator.CreateInstance(accessorType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, args, null);
  1231. }
  1232. public override string ToString() {
  1233. return this.DeclaringType.ToString() + ":" + this.Member.ToString();
  1234. }
  1235. }
  1236. internal class AttributedMetaAssociation : MetaAssociationImpl {
  1237. AttributedMetaDataMember thisMember;
  1238. MetaDataMember otherMember;
  1239. ReadOnlyCollection<MetaDataMember> thisKey;
  1240. ReadOnlyCollection<MetaDataMember> otherKey;
  1241. MetaType otherType;
  1242. bool isMany;
  1243. bool isForeignKey;
  1244. bool isUnique;
  1245. bool isNullable = true;
  1246. bool thisKeyIsPrimaryKey;
  1247. bool otherKeyIsPrimaryKey;
  1248. string deleteRule;
  1249. bool deleteOnNull;
  1250. internal AttributedMetaAssociation(AttributedMetaDataMember member, AssociationAttribute attr) {
  1251. this.thisMember = member;
  1252. this.isMany = TypeSystem.IsSequenceType(this.thisMember.Type);
  1253. Type ot = this.isMany ? TypeSystem.GetElementType(this.thisMember.Type) : this.thisMember.Type;
  1254. this.otherType = this.thisMember.DeclaringType.Model.GetMetaType(ot);
  1255. this.thisKey = (attr.ThisKey != null) ? MakeKeys(this.thisMember.DeclaringType, attr.ThisKey) : this.thisMember.DeclaringType.IdentityMembers;
  1256. this.otherKey = (attr.OtherKey != null) ? MakeKeys(otherType, attr.OtherKey) : this.otherType.IdentityMembers;
  1257. this.thisKeyIsPrimaryKey = AreEqual(this.thisKey, this.thisMember.DeclaringType.IdentityMembers);
  1258. this.otherKeyIsPrimaryKey = AreEqual(this.otherKey, this.otherType.IdentityMembers);
  1259. this.isForeignKey = attr.IsForeignKey;
  1260. this.isUnique = attr.IsUnique;
  1261. this.deleteRule = attr.DeleteRule;
  1262. this.deleteOnNull = attr.DeleteOnNull;
  1263. // if any key members are not nullable, the association is not nullable
  1264. foreach (MetaDataMember mm in thisKey) {
  1265. if (!mm.CanBeNull) {
  1266. this.isNullable = false;
  1267. break;
  1268. }
  1269. }
  1270. // validate DeleteOnNull specification
  1271. if (deleteOnNull == true) {
  1272. if( !(isForeignKey && !isMany && !isNullable) ) {
  1273. throw Error.InvalidDeleteOnNullSpecification(member);
  1274. }
  1275. }
  1276. //validate the number of ThisKey columns is the same as the number of OtherKey columns
  1277. if (this.thisKey.Count != this.otherKey.Count && this.thisKey.Count > 0 && this.otherKey.Count > 0) {
  1278. throw Error.MismatchedThisKeyOtherKey(member.Name, member.DeclaringType.Name);
  1279. }
  1280. // determine reverse reference member
  1281. foreach (MetaDataMember omm in this.otherType.PersistentDataMembers) {
  1282. AssociationAttribute oattr = (AssociationAttribute)Attribute.GetCustomAttribute(omm.Member, typeof(AssociationAttribute));
  1283. if (oattr != null) {
  1284. if (omm != this.thisMember && oattr.Name == attr.Name) {
  1285. this.otherMember = omm;
  1286. break;
  1287. }
  1288. }
  1289. }
  1290. }
  1291. public override MetaType OtherType {
  1292. get { return this.otherType; }
  1293. }
  1294. public override MetaDataMember ThisMember {
  1295. get { return this.thisMember; }
  1296. }
  1297. public override MetaDataMember OtherMember {
  1298. get { return this.otherMember; }
  1299. }
  1300. public override ReadOnlyCollection<MetaDataMember> ThisKey {
  1301. get { return this.thisKey; }
  1302. }
  1303. public override ReadOnlyCollection<MetaDataMember> OtherKey {
  1304. get { return this.otherKey; }
  1305. }
  1306. public override bool ThisKeyIsPrimaryKey {
  1307. get { return this.thisKeyIsPrimaryKey; }
  1308. }
  1309. public override bool OtherKeyIsPrimaryKey {
  1310. get { return this.otherKeyIsPrimaryKey; }
  1311. }
  1312. public override bool IsMany {
  1313. get { return this.isMany; }
  1314. }
  1315. public override bool IsForeignKey {
  1316. get { return this.isForeignKey; }
  1317. }
  1318. public override bool IsUnique {
  1319. get { return this.isUnique; }
  1320. }
  1321. public override bool IsNullable {
  1322. get { return this.isNullable; }
  1323. }
  1324. public override string DeleteRule {
  1325. get { return this.deleteRule; }
  1326. }
  1327. public override bool DeleteOnNull {
  1328. get { return this.deleteOnNull; }
  1329. }
  1330. }
  1331. }