/// <summary> /// Get general info about candidate for repository /// </summary> /// <param name="doClass">Class syntax</param> private BaseCodeClassGeneratorRepository GetRepository(ClassDeclarationSyntax doClass) { var className = doClass.Identifier.Text; // Get DataAccess attribute from repository model var dataAccessAttr = SyntaxAnalysisHelper.GetAttributesAndPropepertiesCollection(doClass).FirstOrDefault(x => x.Name.ToString().Contains(_config.RepositoryAttributeName)); // common repository info var repositoryInfo = new RepositoryInfo() { RepositorySuffix = _config.RepositorySuffix, ClassName = className, ClassFullName = _solutionSyntaxWalker.GetFullRepositoryModelName(doClass), }; repositoryInfo.IsTenantRelated = !doClass.BaseTypeExist("ITenantUnrelated"); // Base class name if (doClass.BaseList != null && doClass.BaseList.Types.Any()) { var baseClass = doClass.BaseList.Types.FirstOrDefault(t => _solutionSyntaxWalker.IsBaseClass(t)); if (baseClass != null) { repositoryInfo.BaseClassName = baseClass.ToString(); } } #region Repository interface // Get implemented interfaces for custom repository (for example - IMenuItemRepository : IRepository<MenuItem>) var repositoryInterfaces = _solutionSyntaxWalker.GetInheritedInterfaces(repositoryInfo.GenericRepositoryInterfaceName).ToList(); var repoInterface = repositoryInterfaces.FirstOrDefault(); if (repoInterface == null) { var ret = CreateWithAnalysisError(className, _config.RepositorySuffix, string.Format("Repository interface {0} not found.", repositoryInfo.GenericRepositoryInterfaceName)); return ret; } // Repository interface info repositoryInfo.RepositoryInterfaceName = _solutionSyntaxWalker.GetTypeNamespace(repoInterface) + "." + repoInterface.Identifier.Text; #endregion #region Repository model attributes #region DataAccess var dataAccess = (DataAccessAttribute)dataAccessAttr; var tableName = dataAccess.TableName ?? doClass.Identifier.ToString() + 's'; repositoryInfo.TableName = tableName; // Get filters var filterKeys = (new[] { dataAccess.FilterKey1, dataAccess.FilterKey2, dataAccess.FilterKey3 }) .Where(fk => fk != null) .Select(fk => { // Filter data may be combined (ItemId, GroupId) var filters = fk.Split(',').Select(f => { var name = f.Trim(); var parameter = doClass.Members.OfType<PropertyDeclarationSyntax>().FirstOrDefault(cp => cp.GetterExist() && cp.SetterExist() && cp.Identifier.Text == name); var fullTypeName = _solutionSyntaxWalker.GetFullPropertyTypeName(parameter); return new ParameterInfo(name, parameter != null ? fullTypeName : null); }).ToList(); return new FilterInfo(string.Join("And", fk.Split(',').Select(f => f.Trim())), filters, FilterType.FilterKey); }); repositoryInfo.FilterInfos.AddRange(filterKeys); // Common filter - isDeleted, modified repositoryInfo.SpecialOptionsIsDeleted = new FilterInfo("IsDeleted", new List<ParameterInfo> {new ParameterInfo("IsDeleted", "bool", Convert.ToString(dataAccess.IsDeleted).FirstSymbolToLower())}, FilterType.FilterKey); repositoryInfo.SpecialOptionsModified = new FilterInfo("Modified", new List<ParameterInfo> {new ParameterInfo("Modified", "DateTimeOffset")}, FilterType.FilterKey); repositoryInfo.VersionTableName = dataAccess.TableVersion; var isVersioning = dataAccess.TableVersion != null; repositoryInfo.IsVersioning = isVersioning; #endregion #endregion #region Property attributes var properties = doClass.Members.OfType<PropertyDeclarationSyntax>().Where(cp => cp.GetterExist() && cp.SetterExist()).ToList(); // Add sql column name - skip members marked [DbIgnoreAttribute] var elements = properties .Where(p => !p.AttributeExist(RepositoryDataModelHelper.DbIgnoreAttributeName)) .Select(p => p.Identifier.Text); repositoryInfo.Elements.AddRange(elements); // Primary keys info var primaryKeys = properties .Where(p => p.AttributeExist(RepositoryDataModelHelper.KeyAttributeName)) .Select(p => { var fullTypeName = _solutionSyntaxWalker.GetFullPropertyTypeName(p); return new ParameterInfo(p.Identifier.Text, fullTypeName); }); repositoryInfo.PrimaryKeys.AddRange(primaryKeys); // Version key var versionKey = properties.FirstOrDefault(p => p.AttributeExist(RepositoryDataModelHelper.VesionKeyAttributeName)); if (versionKey != null) { var keyName = versionKey.Identifier.Text; repositoryInfo.VersionKeyName = keyName; var fullTypeName = _solutionSyntaxWalker.GetFullPropertyTypeName(versionKey); // add filter parameter repositoryInfo.VersionKey = new ParameterInfo(keyName, fullTypeName); } // Many to many var many2ManyInfos = properties .Where(p => p.AttributeExist(RepositoryDataModelHelper.DataMany2ManyAttributeName)) .SelectMany(p => SyntaxAnalysisHelper.GetAttributesAndPropepertiesCollection(p)) .Where(p => p.Name == RepositoryDataModelHelper.DataMany2ManyAttributeName) .Select(p => new Tuple<string, DataMany2ManyAttribute>(p.OwnerElementName, (DataMany2ManyAttribute)p)) .Select(a => new Many2ManyInfo(a.Item1, a.Item2.ManyToManyEntytyType, a.Item2.EntityType)); repositoryInfo.Many2ManyInfo.AddRange(many2ManyInfos); #endregion #region Custom repository // Check exist custom repository class var customRepository = _solutionSyntaxWalker.FindCustomRepositoryClassByName(doClass.Identifier + _config.RepositorySuffix).FirstOrDefault(); var customRepoExist = customRepository != null; List<MethodInfo> customRepositoryMethods = null; // Get custom repository class info if (customRepoExist) { // Custom repository info customRepositoryMethods = customRepository.Members.OfType<MethodDeclarationSyntax>() .Select(m => new MethodInfo() { Name = m.Identifier.Text, ReturnType = m.ReturnType.ToString() }) .ToList(); // Check constructor exist repositoryInfo.IsConstructorImplemented = customRepository.ConstructorImplementationExist(); repositoryInfo.RepositoryNamespace = _solutionSyntaxWalker.GetCustomRepositoryNamespace(customRepository); } var customCacheRepository = _solutionSyntaxWalker.FindCustomRepositoryClassByName(doClass.Identifier + "Cache" + _config.RepositorySuffix).FirstOrDefault(); var customCacheRepositoryExist = customCacheRepository != null; List<MethodInfo> customCacheRepositoryMethods = null; // Get custom cache repository class info if (customCacheRepositoryExist) { // Custom repository info customCacheRepositoryMethods = customCacheRepository.Members.OfType<MethodDeclarationSyntax>() .Select(m => new MethodInfo() { Name = m.Identifier.Text, ReturnType = m.ReturnType.ToString() }) .ToList(); // Check constructor exist repositoryInfo.IsCacheRepositoryConstructorImplemented = customCacheRepository.ConstructorImplementationExist(); if (repositoryInfo.RepositoryNamespace == null) { repositoryInfo.RepositoryNamespace = _solutionSyntaxWalker.GetCustomRepositoryNamespace(customCacheRepository); } } #endregion #region Repository methods // Search method for implementation var repositoryInterfaceMethods = repoInterface.Members.OfType<MethodDeclarationSyntax>() .Select(m => new MethodInfo() { Name = m.Identifier.Text, ReturnType = m.ReturnType.ToString() }) .ToList(); repositoryInfo.InterfaceMethods.AddRange(repositoryInterfaceMethods); if (customRepositoryMethods != null) { repositoryInfo.CustomRepositoryMethodNames.AddRange(customRepositoryMethods); } if (customCacheRepositoryMethods != null) { repositoryInfo.CustomCacheRepositoryMethodNames.AddRange(customCacheRepositoryMethods); } #endregion #region Search required namespace if (repositoryInfo.RepositoryNamespace == null) { repositoryInfo.RepositoryNamespace = _config.DefaultNamespace; } var requiredNamespaces = new List<string> { "System", "System.Collections.Generic", "System.Linq", "System.Threading.Tasks" }; repositoryInfo.RequiredNamespaces.Add(RepositoryType.General, requiredNamespaces); var repositoryInterfaceNamespace = _solutionSyntaxWalker.GetTypeNamespace(repoInterface); repositoryInfo.RequiredNamespaces.Add(RepositoryType.Cache, new List<string> { repositoryInterfaceNamespace }); #endregion var repositoryAndDo = new CodeClassGeneratorRepository { RepositoryInfo = repositoryInfo }; // return general repository return repositoryAndDo; }