Shaolinq.Persistence.TypeDescriptor.TypeDescriptor C# (CSharp) Method

TypeDescriptor() public method

public TypeDescriptor ( TypeDescriptorProvider typeDescriptorProvider, Type type ) : System
typeDescriptorProvider TypeDescriptorProvider
type System.Type
return System
		public TypeDescriptor(TypeDescriptorProvider typeDescriptorProvider, Type type)
		{
			var propertyDescriptorsInOrder = new List<PropertyDescriptor>();
			
			this.Type = type;
			this.TypeDescriptorProvider = typeDescriptorProvider;

			this.DataAccessObjectAttribute = type.GetFirstCustomAttribute<DataAccessObjectAttribute>(true);

			var relatedProperties = new List<PropertyDescriptor>();
			this.relationshipInfos = new List<TypeRelationshipInfo>();
			this.propertyDescriptorByColumnName = new Dictionary<string, PropertyDescriptor>();
			this.propertyDescriptorByPropertyName = new Dictionary<string, PropertyDescriptor>();

			var alreadyEnteredProperties = new HashSet<string>();

			this.PersistedName = this.DataAccessObjectAttribute.GetName(this, this.TypeDescriptorProvider.Configuration.NamingTransforms?.DataAccessObjectName);

			foreach (var propertyInfo in this.GetPropertiesInOrder())
			{
				if (alreadyEnteredProperties.Contains(propertyInfo.Name))
				{
					continue;
				}

				alreadyEnteredProperties.Add(propertyInfo.Name);

				var attribute = (PersistedMemberAttribute)propertyInfo.GetCustomAttributes().FirstOrDefault(c => c is PersistedMemberAttribute);

				if (attribute != null)
				{
					var propertyDescriptor = new PropertyDescriptor(this, type, propertyInfo);

					if (propertyInfo.GetGetMethod() == null)
					{
						throw new InvalidDataAccessObjectModelDefinition("The property {0} is missing a required getter method", propertyInfo.Name);
					}

					if (propertyInfo.GetSetMethod() == null && !propertyDescriptor.IsComputedTextMember && !propertyDescriptor.IsComputedMember)
					{
						throw new InvalidDataAccessObjectModelDefinition("The property {0} is missing a required setter method", propertyInfo.Name);
					}

					if (!IsValidDataType(propertyInfo.PropertyType))
					{
						throw new InvalidDataAccessObjectModelDefinition("The property {0} cannot have a return type of {1}", propertyInfo.Name, propertyInfo.PropertyType.Name);
					}
					
					if (!(propertyInfo.GetGetMethod().IsAbstract || propertyInfo.GetGetMethod().IsVirtual))
					{
						throw new InvalidDataAccessObjectModelDefinition("The property {0} on {1} is not virtual or abstract", propertyInfo.Name, type.Name);
					}

					propertyDescriptorsInOrder.Add(propertyDescriptor);

					this.propertyDescriptorByPropertyName[propertyInfo.Name] = propertyDescriptor;

					if (propertyInfo.GetFirstCustomAttribute<BackReferenceAttribute>(true) != null)
					{
						if (!propertyInfo.PropertyType.IsDataAccessObjectType())
						{
							throw new InvalidDataAccessObjectModelDefinition("The property {0} on {1} is decorated with a BackReference attribute but does not return a type that extends DataAccessObject<OBJECT_TYPE>", propertyInfo.Name, this.Type.Name);
						}

						if (propertyInfo.GetGetMethod() == null)
						{
							throw new InvalidDataAccessObjectModelDefinition("The property {0} is missing a required getter method", propertyInfo.Name);
						}

						if (propertyInfo.GetSetMethod() == null)
						{
							throw new InvalidDataAccessObjectModelDefinition("The property {0} is missing a required setter method", propertyInfo.Name);
						}

						if (!(propertyInfo.GetGetMethod().IsAbstract || propertyInfo.GetGetMethod().IsVirtual))
						{
							throw new InvalidDataAccessObjectModelDefinition("The property {0} on {1} is not virtual or abstract", propertyInfo.Name, type.Name);
						}

						relatedProperties.Add(propertyDescriptor);
					}
				}
			}

			foreach (var propertyInfo in this.Type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
			{
				if (propertyInfo.GetFirstCustomAttribute<DataAccessObjectsAttribute>(true) != null)
				{
					throw new InvalidDataAccessObjectModelDefinition("The property {0} on {1} is decorated with a DataAccessObjects attribute.  Did you mean to you use RelatedDataAccessObjects attribute?", propertyInfo.Name, this.Type.Name);
				}

				if (propertyInfo.GetFirstCustomAttribute<RelatedDataAccessObjectsAttribute>(true) != null)
				{
					if (!typeof(RelatedDataAccessObjects<>).IsAssignableFromIgnoreGenericParameters(propertyInfo.PropertyType.GetGenericTypeDefinition()))
					{
						throw new InvalidDataAccessObjectModelDefinition("The property {0} on {1} is decorated with a RelatedDataAccessObjectsAttribute but the property type does not extend RelatedDataAccessObjects<OBJECT_TYPE>", this.Type.Name, propertyInfo.Name);
					}

					if (propertyInfo.GetSetMethod() != null)
					{
						throw new InvalidDataAccessObjectModelDefinition("The property {0} is a related objects property and should not define a setter method", propertyInfo.Name);
					}

					if (propertyInfo.GetGetMethod() == null)
					{
						throw new InvalidDataAccessObjectModelDefinition("The property {0} is missing a required getter method", propertyInfo.Name);
					}

					if (!(propertyInfo.GetGetMethod().IsAbstract || propertyInfo.GetGetMethod().IsVirtual))
					{
						throw new InvalidDataAccessObjectModelDefinition("The property {0} on {1} is not virtual or abstract", propertyInfo.Name, type.Name);
					}

					var propertyDescriptor = new PropertyDescriptor(this, this.Type, propertyInfo);

					relatedProperties.Add(propertyDescriptor);

					this.propertyDescriptorByPropertyName[propertyInfo.Name] = propertyDescriptor;
				}
			}

			this.PersistedProperties = propertyDescriptorsInOrder;
			this.RelationshipRelatedProperties = relatedProperties.ToReadOnlyCollection();
			this.PersistedPropertiesWithoutBackreferences = this.PersistedProperties.Where(c => !c.IsBackReferenceProperty).ToReadOnlyCollection();
			this.PrimaryKeyProperties = this.PersistedPropertiesWithoutBackreferences.Where(propertyDescriptor => propertyDescriptor.IsPrimaryKey).ToReadOnlyCollection();
			this.ComputedTextProperties = this.PersistedPropertiesWithoutBackreferences.Where(c => c.IsComputedTextMember && !string.IsNullOrEmpty(c.ComputedTextMemberAttribute.Format)).ToReadOnlyCollection();
			this.ComputedProperties = this.PersistedPropertiesWithoutBackreferences.Where(c => c.IsComputedMember && !string.IsNullOrEmpty(c.ComputedMemberAttribute.GetExpression)).ToReadOnlyCollection();
			
			this.PrimaryKeyDerivableProperties = this
				.ComputedProperties
				.Where(c => c.ComputedMemberAssignTarget != null)
				.ToList();
		
			if (this.PrimaryKeyProperties.Count(c => c.IsPropertyThatIsCreatedOnTheServerSide) > 1)
			{
				throw new InvalidDataAccessObjectModelDefinition("An object can only define one integer auto increment property");
			}
		}