/// <summary> /// The function may return permissions for more claims than required. /// </summary> public IEnumerable <PrincipalPermissionInfo> GetPrincipalPermissions(IPrincipal principal, IEnumerable <Guid> claimIds = null) { CsUtility.Materialize(ref claimIds); if (claimIds != null && !claimIds.Any()) { return(Enumerable.Empty <PrincipalPermissionInfo>()); } var query = _principalPermissionRepository.Query() .Where(principalPermission => principalPermission.IsAuthorized != null && principalPermission.PrincipalID == principal.ID); if (claimIds != null && claimIds.Count() < _sqlFilterItemsLimit) { query = query.Where(principalPermission => claimIds.Contains(principalPermission.ClaimID.Value)); } return(query.Select(principalPermission => new PrincipalPermissionInfo { ID = principalPermission.ID, PrincipalID = principalPermission.PrincipalID.Value, ClaimID = principalPermission.ClaimID.Value, IsAuthorized = principalPermission.IsAuthorized.Value, }) .ToList()); }
private static IEnumerable <IConceptInfo> InitializeNonparsablePropertiesRecursive(IAlternativeInitializationConcept alternativeInitializationConcept, HashSet <string> alreadyCreated, int depth, ILogger traceLogger) { if (depth > 10) { throw new DslSyntaxException(alternativeInitializationConcept, "Macro concept references cannot be resolved."); } List <IConceptInfo> result = new List <IConceptInfo>(); IEnumerable <IConceptInfo> createdConcepts; alternativeInitializationConcept.InitializeNonparsableProperties(out createdConcepts); CsUtility.Materialize(ref createdConcepts); if (createdConcepts != null && createdConcepts.Count() > 0) { traceLogger.Trace(() => alternativeInitializationConcept.GetShortDescription() + " generated on alternative initialization: " + string.Join(", ", createdConcepts.Select(c => c.GetShortDescription())) + "."); result.AddRange(createdConcepts); foreach (var concept in createdConcepts.OfType <IAlternativeInitializationConcept>()) { if (!alreadyCreated.Contains(concept.GetFullDescription())) { alreadyCreated.Add(concept.GetFullDescription()); result.AddRange(InitializeNonparsablePropertiesRecursive(concept, alreadyCreated, depth + 1, traceLogger)); } } } return(result); }
/// <summary> /// The function may return permissions for more claims than required. /// </summary> public IEnumerable <RolePermissionInfo> GetRolePermissions(IEnumerable <Guid> roleIds, IEnumerable <Guid> claimIds = null) { CsUtility.Materialize(ref roleIds); CsUtility.Materialize(ref claimIds); if (!roleIds.Any() || (claimIds != null && !claimIds.Any())) { return(Enumerable.Empty <RolePermissionInfo>()); } var query = _rolePermissionRepository.Query() .Where(rolePermission => rolePermission.IsAuthorized != null && roleIds.Contains(rolePermission.RoleID.Value)); if (claimIds != null && claimIds.Count() < _sqlFilterItemsLimit) { query = query.Where(rolePermission => claimIds.Contains(rolePermission.ClaimID.Value)); } return(query.Select(rolePermission => new RolePermissionInfo { ID = rolePermission.ID, RoleID = rolePermission.RoleID.Value, ClaimID = rolePermission.ClaimID.Value, IsAuthorized = rolePermission.IsAuthorized.Value, }) .ToList()); }
/// <summary> /// Clears the roles' authorization data from the cache: RoleRoles, RolePermissions and Role (full list). /// </summary> public void ClearCacheRoles(IEnumerable <Guid> roleIds) { CsUtility.Materialize(ref roleIds); _logger.Trace(() => "ClearCacheRoles: " + string.Join(", ", roleIds) + "."); var deleteKeys = roleIds.Distinct() .Select(roleId => "AuthorizationDataCache.RoleRoles." + roleId.ToString()) .Concat(roleIds.Select(roleId => "AuthorizationDataCache.RolePermissions." + roleId.ToString())) .Concat(new[] { "AuthorizationDataCache.Roles" }); var cache = MemoryCache.Default; foreach (string key in deleteKeys) { cache.Remove(key); } var systemRoles = (IDictionary <SystemRole, Guid>)cache.Get("AuthorizationDataCache.SystemRoles"); if (systemRoles != null && systemRoles.Values.Intersect(roleIds).Any()) { _logger.Trace(() => "ClearCacheRoles: SystemRoles."); cache.Remove("AuthorizationDataCache.SystemRoles"); } }
public static void Save(IEnumerable <InstalledPackage> packages) { CsUtility.Materialize(ref packages); string serialized = JsonConvert.SerializeObject(packages, _serializerSettings); File.WriteAllText(GetPackagesFilePath(), serialized, Encoding.UTF8); }
/// <summary> /// Case-insensitive comparison. /// </summary> public static void AssertContains(string text, IEnumerable <string> patterns, string message = null, string errorContext = null) { CsUtility.Materialize(ref patterns); if (patterns.Any(string.IsNullOrEmpty)) { throw new ArgumentException("Given list of patterns contains an empty string."); } Console.WriteLine("[AssertContains] Text: '" + text + "'."); foreach (var pattern in patterns) { Console.Write("[AssertContains] Looking for pattern '" + pattern + "'."); if (text.ToLower().Contains(pattern.ToLower())) { Console.WriteLine(" Found."); } else { Console.WriteLine(" Not found."); Console.WriteLine(errorContext); Assert.Fail("Text should contain pattern '" + pattern + "'." + (string.IsNullOrEmpty(message) ? " " + message : "") + " " + "The text is '" + text.Limit(200, true) + "'."); } } }
private void LogConcepts(StringBuilder report, string reportName, IEnumerable <IConceptInfo> concepts, bool first = false) { CsUtility.Materialize(ref concepts); if (concepts != null && concepts.Any()) { report.Append(first ? "" : "\r\n").Append(reportName).Append(": ").Append(string.Join(", ", concepts.Select(c => c.GetShortDescription())) + "."); } }
private void LogConcepts(StringBuilder report, string reportName, IEnumerable <IConceptInfo> concepts) { CsUtility.Materialize(ref concepts); if (concepts != null && concepts.Count() > 0) { report.Append("\r\n " + reportName + ": " + string.Join(", ", concepts.Select(c => c.GetShortDescription())) + "."); } }
/// <returns>Result is a List<> of the data structure type. /// The list is returned as IEnumerable<> of the interface type, /// to allow strongly-typed use of the list through TEntityInterface interface. /// Neither List<> or IList<> are covariant, so IEnumerable<> is used.</returns> public IEnumerable <TEntityInterface> CreateList <TSource>(IEnumerable <TSource> source, Action <TSource, TEntityInterface> initializer) { CsUtility.Materialize(ref source); var newItems = CreateList(source.Count()); foreach (var pair in source.Zip(newItems, (sourceItem, newItem) => new { sourceItem, newItem })) { initializer(pair.sourceItem, pair.newItem); } return(newItems); }
/// <summary> /// The function may return more claims than required. /// Note that the result will not include claims that are inactive or do not exist, and that the order of returned items might not match the parameter. /// </summary> public IDictionary <Claim, ClaimInfo> GetClaims(IEnumerable <Claim> requiredClaims = null) { CsUtility.Materialize(ref requiredClaims); if (requiredClaims != null && requiredClaims.Count() == 0) { return(new Dictionary <Claim, ClaimInfo>()); } var queryClaims = _claimRepository.Query().Where(claim => claim.Active != null && claim.Active.Value); if (requiredClaims != null) { var claimsResources = requiredClaims.Select(claim => claim.Resource).Distinct().ToList(); var claimsRights = requiredClaims.Select(claim => claim.Right).Distinct().ToList(); if (claimsResources.Count < _sqlFilterItemsLimit && claimsRights.Count < _sqlFilterItemsLimit) { queryClaims = queryClaims.Where(claim => claimsResources.Contains(claim.ClaimResource) && claimsRights.Contains(claim.ClaimRight)); } } var loadedClaims = queryClaims .Select(claim => new ClaimInfo { ID = claim.ID, Resource = claim.ClaimResource, Right = claim.ClaimRight }) .ToList(); Dictionary <Claim, ClaimInfo> claimsIndex; try { claimsIndex = loadedClaims.ToDictionary(item => new Claim(item.Resource, item.Right)); } catch { var duplicates = loadedClaims.GroupBy(item => new Claim(item.Resource, item.Right)) .Where(g => g.Count() > 1) .FirstOrDefault(); if (duplicates != null) { throw new FrameworkException(string.Format("Loaded duplicate claims: '{0} {1}' and '{2} {3}'.", duplicates.First().Resource, duplicates.First().Right, duplicates.Last().Resource, duplicates.Last().Right)); } throw; } return(claimsIndex); }
public IList <FilterObject> ToFilterObjects(IEnumerable <FilterCriteria> genericFilter) { CsUtility.Materialize(ref genericFilter); foreach (var filter in genericFilter) { ValidateAndPrepare(filter); } var filterObjects = new List <FilterObject>(genericFilter.Count()); bool handledPropertyFilter = false; foreach (var filter in genericFilter) { if (IsPropertyFilter(filter)) { if (!handledPropertyFilter) { handledPropertyFilter = true; filterObjects.Add(CombinePropertyFilters(genericFilter)); } } else { var filterObject = new FilterObject { FilterType = GetSpecificFilterType(filter.Filter), Parameter = filter.Value }; if (string.Equals(filter.Operation, FilterOperationNotMatches, StringComparison.OrdinalIgnoreCase)) { if (ReflectionHelper <IEntity> .GetPredicateExpressionParameter(filterObject.FilterType) != null) { filterObject.Parameter = Not((LambdaExpression)filterObject.Parameter); } else { throw new FrameworkException(FilterOperationNotMatches + " operation is only allowed on a filter expression: Expression<Func<T, bool>>."); } } filterObjects.Add(filterObject); } } return(filterObjects); }
/// <summary> /// Clears the roles' authorization data from the cache: RoleRoles, RolePermissions and Role (full list). /// </summary> public void ClearCacheRoles(IEnumerable <Guid> roleIds) { CsUtility.Materialize(ref roleIds); _logger.Trace(() => "ClearCacheRoles: " + string.Join(", ", roleIds) + "."); var deleteKeys = roleIds.Distinct() .Select(roleId => "AuthorizationDataCache.RoleRoles." + roleId.ToString()) .Concat(roleIds.Select(roleId => "AuthorizationDataCache.RolePermissions." + roleId.ToString())) .Concat(new[] { "AuthorizationDataCache.Roles" }); var cache = MemoryCache.Default; foreach (string key in deleteKeys) { cache.Remove(key); } }
public void SaveConcepts(IEnumerable <IConceptInfo> concepts) { var sw = Stopwatch.StartNew(); CsUtility.Materialize(ref concepts); _performanceLogger.Write(sw, "SaveConcepts: Materialize."); var serializerSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All, ReferenceLoopHandling = ReferenceLoopHandling.Serialize, TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented, }; JsonUtility.SerializeToFile(concepts, DslModelFilePath, serializerSettings); _performanceLogger.Write(sw, "SaveConcepts: Serialize and write."); }
/// <summary> /// Clears the principals' authorization data from the cache: Principal, PrincipalRoles and PrincipalPermissions. /// </summary> public void ClearCachePrincipals(IEnumerable <IPrincipal> principals) { CsUtility.Materialize(ref principals); _logger.Trace(() => "ClearCachePrincipals: " + string.Join(", ", principals.Select(p => p.Name + " " + p.ID.ToString())) + "."); var deleteKeys = principals.Select(principal => "AuthorizationDataCache.Principal." + principal.Name.ToLower()) .Concat(principals.Select(principal => "AuthorizationDataCache.PrincipalRoles." + principal.Name.ToLower() + "." + principal.ID.ToString())) .Concat(principals.Select(principal => "AuthorizationDataCache.PrincipalPermissions." + principal.Name.ToLower() + "." + principal.ID.ToString())) .Distinct(); var cache = MemoryCache.Default; foreach (string key in deleteKeys) { cache.Remove(key); } }
public void SaveConcepts(IEnumerable <IConceptInfo> concepts) { var sw = Stopwatch.StartNew(); var serializerSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All, ReferenceLoopHandling = ReferenceLoopHandling.Serialize, TypeNameHandling = TypeNameHandling.All, }; CsUtility.Materialize(ref concepts); string serializedConcepts = JsonConvert.SerializeObject(concepts, serializerSettings); string path = Path.Combine(Paths.GeneratedFolder, DslModelFileName); File.WriteAllText(path, serializedConcepts, Encoding.UTF8); _performanceLogger.Write(sw, "DslModelFile.Save."); }
public void ExecuteSql(IEnumerable <string> commands, bool useTransaction, Action <int> beforeExecute, Action <int> afterExecute) { CsUtility.Materialize(ref commands); _logger.Trace(() => "Executing " + commands.Count() + " commands" + (useTransaction ? "" : " without transaction") + "."); SafeExecuteCommand( com => { int count = 0; foreach (var sql in commands) { count++; if (sql == null) { throw new FrameworkException("SQL script is null."); } _logger.Trace(() => "Executing command: " + sql); if (string.IsNullOrWhiteSpace(sql)) { continue; } var sw = Stopwatch.StartNew(); try { com.CommandText = sql; beforeExecute?.Invoke(count - 1); com.ExecuteNonQuery(); } finally { afterExecute?.Invoke(count - 1); LogPerformanceIssue(sw, sql); } } CheckTransactionState(useTransaction, com, commands); }, useTransaction); }
/// <summary> /// Note that the result will not include roles that do not exist, and that the order of returned items might not match the parameter. /// </summary> public IDictionary <Guid, string> GetRoles(IEnumerable <Guid> roleIds = null) { CsUtility.Materialize(ref roleIds); if (roleIds != null && !roleIds.Any()) { return(new Dictionary <Guid, string>()); } var query = _roleRepository.Query(); if (roleIds != null) { query = query.Where(role => roleIds.Contains(role.ID)); } return(query .Select(role => new { role.ID, role.Name }) // This select avoids loading extra columns from database. .ToDictionary(role => role.ID, role => role.Name)); }
public static void Save(IEnumerable <InstalledPackage> packages) { CsUtility.Materialize(ref packages); // Package folder is saved as relative path, to allow moving the deployed folder. foreach (var package in packages) { package.SetRelativeFolderPath(); } string serialized = JsonConvert.SerializeObject(packages, _serializerSettings); foreach (var package in packages) { package.SetAbsoluteFolderPath(); } File.WriteAllText(PackagesFilePath, serialized, Encoding.UTF8); }
/// <summary> /// Note that the result will not include roles that do not exist, and that the order of returned items might not match the parameter. /// </summary> public IDictionary <Guid, string> GetRoles(IEnumerable <Guid> roleIds = null) { CsUtility.Materialize(ref roleIds); if (roleIds != null && roleIds.Count() == 0) { return(new Dictionary <Guid, string>()); } var query = _roleRepository.Query(); if (roleIds != null) { query = query.Where(role => roleIds.Contains(role.ID)); } return(query .Select(role => new { ID = role.ID, Name = role.Name }) .ToList() .ToDictionary(role => role.ID, role => role.Name)); }
/// <param name="sameRecord">Compare key properties, determining the records that should be inserted or deleted. /// Typical implementation: /// <code> /// class CompareName : IComparer<ISomeEntity> /// { /// public int Compare(ISomeEntity x, ISomeEntity y) { return string.Compare(x.Name, y.Name, StringComparison.InvariantCultureIgnoreCase); } /// } /// </code></param> /// <param name="sameValue">Compare other properties, determining the records that should be updated. /// Comparison may also include key properties with stricter constraints (such as case sensitivity). /// Typical implementation: /// <code>(x, y) => x.Name == y.Name && x.SomeValue == y.SomeValue;</code></param> /// <param name="filterLoad">For supported filters types see <see cref="Load{TParameter}(TParameter)"/> function.</param> /// <param name="assign">Typical implementation: /// <code>(destination, source) => { /// destination.Property1 = source.Property1; /// destination.Property2 = source.Property2; }</code></param> /// <param name="beforeSave"><code>(toInsert, toUpdate, toDelete) => { some code; } </code></param> public void InsertOrUpdateOrDelete( IEnumerable <TEntityInterface> newItems, IComparer <TEntityInterface> sameRecord, Func <TEntityInterface, TEntityInterface, bool> sameValue, object filterLoad, Action <TEntityInterface, TEntityInterface> assign, BeforeSave beforeSave = null) { var stopwatch = Stopwatch.StartNew(); // Initialize new items: CsUtility.Materialize(ref newItems); _performanceLogger.Write(stopwatch, () => string.Format("{0}.InsertOrUpdateOrDelete: Initialize new items ({1})", _repositoryName, newItems.Count())); // Load old items: IEnumerable <TEntityInterface> oldItems = this.Load(filterLoad); _performanceLogger.Write(stopwatch, () => string.Format("{0}.InsertOrUpdateOrDelete: Load old items ({1})", _repositoryName, oldItems.Count())); // Compare new and old items: IEnumerable <TEntityInterface> toInsert, toUpdate, toDelete; Diff(oldItems, newItems, sameRecord, sameValue, assign, out toInsert, out toUpdate, out toDelete); _performanceLogger.Write(stopwatch, () => string.Format("{0}.InsertOrUpdateOrDelete: Diff ({1} new items, {2} old items, {3} to insert, {4} to update, {5} to delete)", _repositoryName, newItems.Count(), oldItems.Count(), toInsert.Count(), toUpdate.Count(), toDelete.Count())); // Modify old items to match new items: if (beforeSave != null) { beforeSave(ref toInsert, ref toUpdate, ref toDelete); } Save(toInsert, toUpdate, toDelete); _performanceLogger.Write(stopwatch, () => string.Format("{0}.InsertOrUpdateOrDelete: Save ({1} new items, {2} old items, {3} to insert, {4} to update, {5} to delete)", _repositoryName, newItems.Count(), oldItems.Count(), toInsert.Count(), toUpdate.Count(), toDelete.Count())); }
/// <param name="sameRecord">Compare key properties, determining the records that should be inserted or deleted. /// If set to null, the items will be compared by the ID property. /// Typical implementation: /// <code> /// class CompareName : IComparer<ISomeEntity> /// { /// public int Compare(ISomeEntity x, ISomeEntity y) { return string.Compare(x.Name, y.Name, StringComparison.InvariantCultureIgnoreCase); } /// } /// </code></param> /// <param name="sameValue">Compare other properties, determining the records that should be updated. /// Comparison may also include key properties with stricter constraints (such as case sensitivity). /// Typical implementation: /// <code>(x, y) => x.Name == y.Name && x.SomeValue == y.SomeValue;</code></param> /// <param name="filterLoad">For supported filters types see <see cref="Load"/> function.</param> /// <param name="assign">Typical implementation: /// <code>(destination, source) => { /// destination.Property1 == source.Property1; /// destination.Property2 == source.Property2; }</code></param> /// <param name="filterDeactivateDeleted">A filter that selects items that should be deactivated instead of deleted. /// Typical implementation: /// <code>(Func<IEntity, bool>)(item => ItemsInUseHashSet.Contains(item.ID))</code> /// <br/>For supported filters types see <see cref="Filter"/> function. /// </param> /// <param name="beforeSave"><code>(toInsert, toUpdate, toDelete) => { some code; } </code></param> public void InsertOrUpdateOrDeleteOrDeactivate( IEnumerable <TEntityInterface> newItems, IComparer <TEntityInterface> sameRecord, Func <TEntityInterface, TEntityInterface, bool> sameValue, object filterLoad, Action <TEntityInterface, TEntityInterface> assign, object filterDeactivateDeleted, BeforeSave beforeSave = null) { var stopwatch = Stopwatch.StartNew(); // Initialize new items: CsUtility.Materialize(ref newItems); foreach (var newItem in newItems.Cast <IDeactivatable>()) { if (newItem.Active == null) { newItem.Active = true; } } _performanceLogger.Write(stopwatch, () => $"InsertOrUpdateOrDeleteOrDeactivate: Initialize new items ({newItems.Count()})"); // Load old items: IEnumerable <TEntityInterface> oldItems = this.Load(filterLoad); _performanceLogger.Write(stopwatch, () => $"InsertOrUpdateOrDeleteOrDeactivate: Load old items ({oldItems.Count()})"); // Compare new and old items: IEnumerable <TEntityInterface> toInsert, toUpdate, toDelete; Diff(oldItems, newItems, sameRecord, sameValue, assign, out toInsert, out toUpdate, out toDelete); _performanceLogger.Write(stopwatch, () => $"InsertOrUpdateOrDeleteOrDeactivate: Diff ({newItems.Count()} new items, {oldItems.Count()} old items, {toInsert.Count()} to insert, {toUpdate.Count()} to update, {toDelete.Count()} to delete)"); // Deactivate some items instead of deleting: IEnumerable <TEntityInterface> toDeactivate = Filter(toDelete, filterDeactivateDeleted); int activeToDeactivateCount = 0; if (toDeactivate.Any()) { int oldDeleteCount = toDelete.Count(); // Don't delete items that should be deactivated: if (toDeactivate.Count() == oldDeleteCount) { toDelete = CreateList(0); } else { var toDeactivateIndex = new HashSet <TEntityInterface>(toDeactivate, new InstanceComparer()); toDelete = Reflection.ToListOfEntity(toDelete.Where(item => !toDeactivateIndex.Contains(item))); } if (toDelete.Count() + toDeactivate.Count() != oldDeleteCount) { throw new FrameworkException($"Invalid number of items to deactivate for '{_genericRepositoryName}'." + $" Verify if the deactivation filter ({filterDeactivateDeleted.GetType().FullName}) on that data structure returns a valid subset of the given items." + $" {oldDeleteCount} items to remove: {toDeactivate.Count()} items to deactivate and {toDelete.Count()} items remaining to delete (should be {oldDeleteCount - toDeactivate.Count()})."); } // Update the items to deactivate (unless already deactivated): var activeToDeactivate = toDeactivate.Cast <IDeactivatable>().Where(item => item.Active == null || item.Active == true).ToList(); foreach (var item in activeToDeactivate) { item.Active = false; } Reflection.AddRange(toUpdate, Reflection.CastAsEntity(activeToDeactivate)); activeToDeactivateCount = activeToDeactivate.Count; } _performanceLogger.Write(stopwatch, () => $"InsertOrUpdateOrDeleteOrDeactivate: Deactivate ({activeToDeactivateCount} to deactivate, {toDeactivate.Count() - activeToDeactivateCount} already deactivated)"); // Modify old items to match new items: if (beforeSave != null) { beforeSave(ref toInsert, ref toUpdate, ref toDelete); CsUtility.Materialize(ref toInsert); CsUtility.Materialize(ref toUpdate); CsUtility.Materialize(ref toDelete); } Save(toInsert, toUpdate, toDelete); _performanceLogger.Write(stopwatch, () => $"InsertOrUpdateOrDeleteOrDeactivate: Save ({newItems.Count()} new items, {oldItems.Count()} old items, {toInsert.Count()} to insert, {toUpdate.Count()} to update, {toDelete.Count()} to delete)"); }
public static void UpdateCodes <T>(ISqlExecuter sqlExecuter, string entityName, string propertyName, IEnumerable <AutoCodeItem <T> > autoCodeItems, Action <T, string> setCode) where T : IEntity { CsUtility.Materialize(ref autoCodeItems); var parsedAutoCode = autoCodeItems .Where(acItem => !string.IsNullOrEmpty(acItem.Code)) .Select(acItem => { int numberOfPluses = GetNumberOfPluses(acItem.Code, acItem.Item.ID, entityName, propertyName); if (numberOfPluses > 0) { return new { acItem.Item, acItem.Grouping, Prefix = acItem.Code.Substring(0, acItem.Code.Length - numberOfPluses), MinDigits = numberOfPluses, ProvidedCodeValue = (int?)null } } ; int suffixDigitsCount = GetSuffixDigitsCount(acItem.Code); if (suffixDigitsCount > 0) { return new { acItem.Item, acItem.Grouping, Prefix = acItem.Code.Substring(0, acItem.Code.Length - suffixDigitsCount), MinDigits = suffixDigitsCount, ProvidedCodeValue = (int?)int.Parse(acItem.Code.Substring(acItem.Code.Length - suffixDigitsCount)) } } ; return(null); }) .Where(acItem => acItem != null) .ToList(); var autoCodeGroups = parsedAutoCode .GroupBy(acItem => new { acItem.Grouping, acItem.Prefix }) .Select(g => new { g.Key.Grouping, g.Key.Prefix, MinDigits = g.Max(acItem => acItem.MinDigits), ItemsToGenerateCode = g.Where(acItem => acItem.ProvidedCodeValue == null).Select(acItem => acItem.Item).ToList(), MaxProvidedCode = g.Max(acItem => acItem.ProvidedCodeValue) }) .OrderBy(acGroup => acGroup.Grouping) .ThenBy(acGroup => acGroup.Prefix) .ToList(); foreach (var autoCodeGroup in autoCodeGroups) { if (autoCodeGroup.MaxProvidedCode != null) { string sql = string.Format("EXEC Common.UpdateAutoCodeCache {0}, {1}, {2}, {3}, {4}, {5}", Rhetos.Utilities.SqlUtility.QuoteText(entityName), Rhetos.Utilities.SqlUtility.QuoteText(propertyName), Rhetos.Utilities.SqlUtility.QuoteText(autoCodeGroup.Grouping), Rhetos.Utilities.SqlUtility.QuoteText(autoCodeGroup.Prefix), autoCodeGroup.MinDigits, autoCodeGroup.MaxProvidedCode); sqlExecuter.ExecuteSql(sql); } if (autoCodeGroup.ItemsToGenerateCode.Count > 0) { string sql = string.Format("EXEC Common.GetNextAutoCodeCached {0}, {1}, {2}, {3}, {4}, {5}", Rhetos.Utilities.SqlUtility.QuoteText(entityName), Rhetos.Utilities.SqlUtility.QuoteText(propertyName), Rhetos.Utilities.SqlUtility.QuoteText(autoCodeGroup.Grouping), Rhetos.Utilities.SqlUtility.QuoteText(autoCodeGroup.Prefix), autoCodeGroup.MinDigits, autoCodeGroup.ItemsToGenerateCode.Count); int?minDigits = null; int?lastCode = null; sqlExecuter.ExecuteReader(sql, reader => { minDigits = reader.GetInt32(0); lastCode = reader.GetInt32(1); }); for (int i = 0; i < autoCodeGroup.ItemsToGenerateCode.Count; i++) { string codeSuffix = (lastCode.Value - autoCodeGroup.ItemsToGenerateCode.Count + i + 1).ToString(); if (codeSuffix.Length < minDigits.Value) { codeSuffix = new string('0', minDigits.Value - codeSuffix.Length) + codeSuffix; } setCode(autoCodeGroup.ItemsToGenerateCode[i], autoCodeGroup.Prefix + codeSuffix); } } } }
private void ExpandMacroConcepts(DslContainer dslContainer) { var swTotal = Stopwatch.StartNew(); var sw = Stopwatch.StartNew(); int iteration = 0; var iterationCreatedConcepts = new List <IConceptInfo>(); int lastNewConceptTime = 0; var lastNewConceptTimeByIteration = new List <int>(); var lastNewConceptTimeByMacro = new Dictionary <string, int>(); var recommendedMacroOrder = _macroOrderRepository.Load().ToDictionary(m => m.EvaluatorName, m => m.EvaluatorOrder); var macroEvaluators = ListMacroEvaluators(recommendedMacroOrder); var macroStopwatches = macroEvaluators.ToDictionary(macro => macro.Name, macro => new Stopwatch()); var createdTypesInIteration = new List <CreatedTypesInIteration>(dslContainer.Concepts.Count() * 5); _performanceLogger.Write(sw, "ExpandMacroConcepts initialization (" + macroEvaluators.Count + " evaluators, " + dslContainer.Concepts.Count() + " parsed concepts resolved, " + dslContainer.UnresolvedConceptsCount() + " unresolved)."); do { iteration++; if (iteration > MacroIterationLimit) { throw new DslSyntaxException(string.Format( "Possible infinite loop detected with recursive macro concept {1}. Iteration limit ({0}) exceeded while expanding macro.", MacroIterationLimit, iterationCreatedConcepts.First().GetShortDescription())); } iterationCreatedConcepts.Clear(); _logger.Trace("Expanding macro concepts, iteration {0}.", iteration); foreach (var macroEvaluator in macroEvaluators) { macroStopwatches[macroEvaluator.Name].Start(); foreach (var conceptInfo in dslContainer.FindByType(macroEvaluator.Implements, macroEvaluator.ImplementsDerivations).ToList()) { var macroCreatedConcepts = macroEvaluator.Evaluate(conceptInfo, dslContainer); CsUtility.Materialize(ref macroCreatedConcepts); if (macroCreatedConcepts != null && macroCreatedConcepts.Any()) { _logger.Trace(() => "Evaluating macro " + macroEvaluator.Name + " on " + conceptInfo.GetShortDescription() + "."); var aiCreatedConcepts = AlternativeInitialization.InitializeNonparsableProperties(macroCreatedConcepts, _logger); var newUniqueConcepts = dslContainer.AddNewConceptsAndReplaceReferences(aiCreatedConcepts); newUniqueConcepts.AddRange(dslContainer.AddNewConceptsAndReplaceReferences(macroCreatedConcepts)); _logger.Trace(() => LogCreatedConcepts(dslContainer, macroCreatedConcepts, newUniqueConcepts)); iterationCreatedConcepts.AddRange(newUniqueConcepts); // Optimization analysis: if (newUniqueConcepts.Count > 0) { lastNewConceptTimeByMacro[macroEvaluator.Name] = ++lastNewConceptTime; } createdTypesInIteration.AddRange(newUniqueConcepts.Select(nuc => new CreatedTypesInIteration { Macro = macroEvaluator.Name, Created = nuc.BaseConceptInfoType().Name, Iteration = iteration })); } } macroStopwatches[macroEvaluator.Name].Stop(); } lastNewConceptTimeByIteration.Add(lastNewConceptTime); _performanceLogger.Write(sw, "ExpandMacroConcepts iteration " + iteration + " (" + iterationCreatedConcepts.Count + " new concepts, " + dslContainer.UnresolvedConceptsCount() + " left unresolved)."); } while (iterationCreatedConcepts.Count > 0); _evaluatorsOrderLogger.Trace(() => swTotal.Elapsed + "\r\n" + ReportLastEvaluationOrder(lastNewConceptTimeByMacro, lastNewConceptTimeByIteration)); foreach (var macroStopwatch in macroStopwatches.OrderByDescending(msw => msw.Value.Elapsed.TotalSeconds).Take(5)) { _performanceLogger.Write(macroStopwatch.Value, () => "ExpandMacroConcepts total time for " + macroStopwatch.Key + "."); } _logger.Trace(() => LogCreatedTypesInIteration(createdTypesInIteration)); dslContainer.ReportErrorForUnresolvedConcepts(); SaveMacroEvaluationOrder(lastNewConceptTimeByMacro); _performanceLogger.Write(swTotal, "ExpandMacroConcepts."); }