PageRenderTime 4799ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Signum.Engine/Basics/TypeLogic.cs

http://github.com/signumframework/signumframework
C# | 253 lines | 206 code | 47 blank | 0 comment | 12 complexity | 2eca91df62577f33692179c5f22ee31e MD5 | raw file
Possible License(s): LGPL-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Signum.Entities;
  5. using Signum.Engine.Maps;
  6. using Signum.Entities.Reflection;
  7. using Signum.Utilities;
  8. using System.Reflection;
  9. using Signum.Entities.Basics;
  10. using Signum.Engine.DynamicQuery;
  11. using Signum.Utilities.Reflection;
  12. namespace Signum.Engine.Basics
  13. {
  14. public static class TypeLogic
  15. {
  16. public static Dictionary<PrimaryKey, Type> IdToType
  17. {
  18. get { return Schema.Current.typeCachesLazy.Value.IdToType; }
  19. }
  20. public static Dictionary<Type, PrimaryKey> TypeToId
  21. {
  22. get { return Schema.Current.typeCachesLazy.Value.TypeToId; }
  23. }
  24. public static Dictionary<Type, TypeEntity> TypeToEntity
  25. {
  26. get { return Schema.Current.typeCachesLazy.Value.TypeToEntity; }
  27. }
  28. public static Dictionary<TypeEntity, Type> EntityToType
  29. {
  30. get { return Schema.Current.typeCachesLazy.Value.EntityToType; }
  31. }
  32. public static void AssertStarted(SchemaBuilder sb)
  33. {
  34. sb.AssertDefined(ReflectionTools.GetMethodInfo(() => Start(null!)));
  35. }
  36. public static void Start(SchemaBuilder sb)
  37. {
  38. if (sb.NotDefined(MethodInfo.GetCurrentMethod()))
  39. {
  40. Schema schema = Schema.Current;
  41. sb.Include<TypeEntity>()
  42. .WithQuery(() => t => new
  43. {
  44. Entity = t,
  45. t.Id,
  46. t.TableName,
  47. t.CleanName,
  48. t.ClassName,
  49. t.Namespace,
  50. });
  51. schema.SchemaCompleted += () =>
  52. {
  53. var attributes = schema.Tables.Keys.Select(t => KeyValuePair.Create(t, t.GetCustomAttribute<EntityKindAttribute>(true))).ToList();
  54. var errors = attributes.Where(a => a.Value == null).ToString(a => "Type {0} does not have an EntityTypeAttribute".FormatWith(a.Key.Name), "\r\n");
  55. if (errors.HasText())
  56. throw new InvalidOperationException(errors);
  57. };
  58. schema.Initializing += () =>
  59. {
  60. schema.typeCachesLazy.Load();
  61. };
  62. schema.typeCachesLazy = sb.GlobalLazy(() => new TypeCaches(schema), new InvalidateWith(typeof(TypeEntity)), Schema.Current.InvalidateMetadata);
  63. TypeEntity.SetTypeEntityCallbacks(
  64. t => TypeToEntity.GetOrThrow(t),
  65. t => EntityToType.GetOrThrow(t));
  66. }
  67. }
  68. public static Dictionary<TypeEntity, Type> TryEntityToType(Replacements replacements)
  69. {
  70. return (from dn in Administrator.TryRetrieveAll<TypeEntity>(replacements)
  71. join t in Schema.Current.Tables.Keys on dn.FullClassName equals (EnumEntity.Extract(t) ?? t).FullName
  72. select (dn, t)).ToDictionary(a => a.dn, a => a.t);
  73. }
  74. public static SqlPreCommand? Schema_Synchronizing(Replacements replacements)
  75. {
  76. var schema = Schema.Current;
  77. var isPostgres = schema.Settings.IsPostgres;
  78. Dictionary<string, TypeEntity> should = GenerateSchemaTypes().ToDictionaryEx(s => s.TableName, "tableName in memory");
  79. var currentList = Administrator.TryRetrieveAll<TypeEntity>(replacements);
  80. { //External entities are nt asked in SchemaSynchronizer
  81. replacements.AskForReplacements(
  82. currentList.Where(t => schema.IsExternalDatabase(ObjectName.Parse(t.TableName, isPostgres).Schema.Database)).Select(a => a.TableName).ToHashSet(),
  83. should.Values.Where(t => schema.IsExternalDatabase(ObjectName.Parse(t.TableName, isPostgres).Schema.Database)).Select(a => a.TableName).ToHashSet(),
  84. Replacements.KeyTables);
  85. }
  86. Dictionary<string, TypeEntity> current = ApplyReplacementsToOld(replacements,
  87. currentList.ToDictionaryEx(c => c.TableName, "tableName in database"), Replacements.KeyTables);
  88. { //Temporal solution until applications are updated
  89. var repeated =
  90. should.Keys.Select(k => ObjectName.Parse(k, isPostgres)).GroupBy(a => a.Name).Where(a => a.Count() > 1).Select(a => a.Key).Concat(
  91. current.Keys.Select(k => ObjectName.Parse(k, isPostgres)).GroupBy(a => a.Name).Where(a => a.Count() > 1).Select(a => a.Key)).ToList();
  92. Func<string, string> simplify = tn =>
  93. {
  94. ObjectName name = ObjectName.Parse(tn, isPostgres);
  95. return repeated.Contains(name.Name) ? name.ToString() : name.Name;
  96. };
  97. should = should.SelectDictionary(simplify, v => v);
  98. current = current.SelectDictionary(simplify, v => v);
  99. }
  100. Table table = schema.Table<TypeEntity>();
  101. using (replacements.WithReplacedDatabaseName())
  102. return Synchronizer.SynchronizeScript(
  103. Spacing.Double,
  104. should,
  105. current,
  106. createNew: (tn, s) => table.InsertSqlSync(s),
  107. removeOld: (tn, c) => table.DeleteSqlSync(c, t => t.CleanName == c.CleanName),
  108. mergeBoth: (tn, s, c) =>
  109. {
  110. var originalCleanName = c.CleanName;
  111. var originalFullName = c.FullClassName;
  112. if (c.TableName != s.TableName)
  113. {
  114. var pc = ObjectName.Parse(c.TableName, isPostgres);
  115. var ps = ObjectName.Parse(s.TableName, isPostgres);
  116. if (!EqualsIgnoringDatabasePrefix(pc, ps))
  117. {
  118. c.TableName = ps.ToString();
  119. }
  120. }
  121. c.CleanName = s.CleanName;
  122. c.Namespace = s.Namespace;
  123. c.ClassName = s.ClassName;
  124. return table.UpdateSqlSync(c, t => t.CleanName == originalCleanName, comment: originalFullName);
  125. });
  126. }
  127. static bool EqualsIgnoringDatabasePrefix(ObjectName pc, ObjectName ps) =>
  128. ps.Name == pc.Name &&
  129. pc.Schema.Name == ps.Schema.Name &&
  130. Suffix(pc.Schema.Database?.Name) == Suffix(ps.Schema.Database?.Name);
  131. static string? Suffix(string? name) => name.TryAfterLast("_") ?? name;
  132. static Dictionary<string, O> ApplyReplacementsToOld<O>(this Replacements replacements, Dictionary<string, O> oldDictionary, string replacementsKey)
  133. {
  134. if (!replacements.ContainsKey(replacementsKey))
  135. return oldDictionary;
  136. Dictionary<string, string> dic = replacements[replacementsKey];
  137. return oldDictionary.SelectDictionary(a => dic.TryGetC(a) ?? a, v => v);
  138. }
  139. internal static SqlPreCommand Schema_Generating()
  140. {
  141. Table table = Schema.Current.Table<TypeEntity>();
  142. return GenerateSchemaTypes()
  143. .Select((e, i) => table.InsertSqlSync(e, suffix: i.ToString()))
  144. .Combine(Spacing.Simple)!
  145. .PlainSqlCommand();
  146. }
  147. internal static List<TypeEntity> GenerateSchemaTypes()
  148. {
  149. var list = (from tab in Schema.Current.Tables.Values
  150. let type = EnumEntity.Extract(tab.Type) ?? tab.Type
  151. select new TypeEntity
  152. {
  153. TableName = tab.Name.ToString(),
  154. CleanName = Reflector.CleanTypeName(type),
  155. Namespace = type.Namespace!,
  156. ClassName = type.Name,
  157. }).ToList();
  158. return list;
  159. }
  160. public static Dictionary<string, Type> NameToType
  161. {
  162. get { return Schema.Current.NameToType; }
  163. }
  164. public static Dictionary<Type, string> TypeToName
  165. {
  166. get { return Schema.Current.TypeToName; }
  167. }
  168. public static Type GetType(string cleanName)
  169. {
  170. return NameToType.GetOrThrow(cleanName, "Type {0} not found in the schema");
  171. }
  172. public static Type? TryGetType(string cleanName)
  173. {
  174. return NameToType.TryGetC(cleanName);
  175. }
  176. public static string GetCleanName(Type type)
  177. {
  178. return TypeToName.GetOrThrow(type, "Type {0} not found in the schema");
  179. }
  180. public static string? TryGetCleanName(Type type)
  181. {
  182. return TypeToName.TryGetC(type);
  183. }
  184. }
  185. internal class TypeCaches
  186. {
  187. public readonly Dictionary<Type, TypeEntity> TypeToEntity;
  188. public readonly Dictionary<TypeEntity, Type> EntityToType;
  189. public readonly Dictionary<PrimaryKey, Type> IdToType;
  190. public readonly Dictionary<Type, PrimaryKey> TypeToId;
  191. public TypeCaches(Schema current)
  192. {
  193. TypeToEntity = EnumerableExtensions.JoinRelaxed(
  194. Database.RetrieveAll<TypeEntity>(),
  195. current.Tables.Keys,
  196. t => t.FullClassName,
  197. t => (EnumEntity.Extract(t) ?? t).FullName,
  198. (typeEntity, type) => (typeEntity, type),
  199. "caching {0}".FormatWith(current.Table(typeof(TypeEntity)).Name)
  200. ).ToDictionary(a => a.type, a => a.typeEntity);
  201. EntityToType = TypeToEntity.Inverse();
  202. TypeToId = TypeToEntity.SelectDictionary(k => k, v => v.Id);
  203. IdToType = TypeToId.Inverse();
  204. }
  205. }
  206. }