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");
}
}