private async Task <Type> BuildNestedTypeAsync(EntityPropertyDto propertyDto, DynamicDtoTypeBuildingContext context) { if (propertyDto.DataType != DataTypes.Object) { throw new NotSupportedException($"{nameof(BuildNestedTypeAsync)}: unsupported type of property (expected '{DataTypes.Object}', actual: '{propertyDto.DataType}')"); } // todo: build name of the class according ot the level of the property using (context.OpenNamePrefix(propertyDto.Name)) { var className = context.CurrentPrefix.Replace('.', '_'); var tb = GetTypeBuilder(typeof(object), className, new List <Type> { typeof(IDynamicNestedObject) }); var constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); foreach (var property in propertyDto.Properties) { //if (propertyFilter == null || propertyFilter.Invoke(property.PropertyName)) var propertyType = await GetDtoPropertyTypeAsync(property, context); CreateProperty(tb, property.Name, propertyType); } var objectType = tb.CreateType(); context.ClassCreated(objectType); return(objectType); } }
// todo: get IsVersioned flag from the EntityPropertyDto public async Task SetValueAsync <TId>(IEntity <TId> entity, EntityPropertyDto property, string value, bool createNewVersion) { var config = entity.GetType().GetEntityConfiguration(); var prop = _entityPropertyValueRepository.GetAll() .Where(x => x.EntityProperty.Id == property.Id && x.OwnerId == entity.Id.ToString() && x.OwnerType == config.TypeShortAlias) .OrderByDescending(x => x.CreationTime).FirstOrDefault(); if (prop?.Value == value) { return; } if (createNewVersion || prop == null) { prop = new EntityPropertyValue() { Value = value, EntityProperty = _entityPropertyRepository.Get(property.Id) }; prop.SetOwner(entity); } else { prop.Value = value; } await _entityPropertyValueRepository.InsertOrUpdateAsync(prop); }
public async Task <string> GetValueAsync <TId>(IEntity <TId> entity, EntityPropertyDto property) { var config = entity.GetType().GetEntityConfiguration(); var result = await _entityPropertyValueRepository.GetAll() .Where(x => x.EntityProperty.Id == property.Id && x.OwnerId == entity.Id.ToString() && x.OwnerType == config.TypeShortAlias) .OrderByDescending(x => x.CreationTime).FirstOrDefaultAsync(); return(result?.Value); }
/// inheritedDoc public string SerializeProperty(EntityPropertyDto propertyDto, object value) { switch (propertyDto.DataType) { case DataTypes.Date: { var settings = new JsonSerializerSettings() { Converters = new List <JsonConverter>() { new IsoDateTimeConverter() { DateTimeFormat = "yyyy'-'MM'-'dd" } }, }; return(JsonConvert.SerializeObject(value, settings)); } default: return(JsonConvert.SerializeObject(value)); } }
private Type GetEntityReferenceType(EntityPropertyDto propertyDto, DynamicDtoTypeBuildingContext context) { if (propertyDto.DataType != DataTypes.EntityReference) { throw new NotSupportedException($"DataType {propertyDto.DataType} is not supported. Expected {DataTypes.EntityReference}"); } if (string.IsNullOrWhiteSpace(propertyDto.EntityType)) { return(null); } var entityConfig = _entityConfigurationStore.Get(propertyDto.EntityType); if (entityConfig == null) { return(null); } return(context.UseDtoForEntityReferences ? typeof(EntityWithDisplayNameDto <>).MakeGenericType(entityConfig.IdType) : entityConfig?.IdType); }
public async Task BuildDynamicDto_Test() { var entityConfigCacheMock = new Mock <IEntityConfigCache>(); const string supervisorPropName = "Supervisor"; const string supervisorFirstNamePropName = "FirstName"; const string supervisorLastNamePropName = "LastName"; entityConfigCacheMock.Setup(x => x.GetEntityPropertiesAsync(It.IsAny <Type>())) .Returns(() => { var result = new EntityPropertyDtoList(); result.AddString("Name", "Name..."); result.AddString("Description", "Description..."); var nested = new EntityPropertyDto { Name = supervisorPropName, DataType = DataTypes.Object, Properties = new List <EntityPropertyDto>(), }; nested.Properties.Add(new EntityPropertyDto { Name = supervisorFirstNamePropName, DataType = DataTypes.String }); nested.Properties.Add(new EntityPropertyDto { Name = supervisorLastNamePropName, DataType = DataTypes.String }); result.Add(nested); var r = result as List <EntityPropertyDto>; return(Task.FromResult(r)); }); var entityConfigStore = LocalIocManager.Resolve <IEntityConfigurationStore>(); var cacheManager = LocalIocManager.Resolve <ICacheManager>(); var builder = new DynamicDtoTypeBuilder(entityConfigCacheMock.Object, entityConfigStore, cacheManager); var baseDtoType = typeof(DynamicDto <Person, Guid>); var context = new DynamicDtoTypeBuildingContext() { ModelType = baseDtoType, // AddFormFieldsProperty = false // note: false is a default value for AddFormFieldsProperty. Leave it blank to test default value }; var proxyType = await builder.BuildDtoFullProxyTypeAsync(baseDtoType, context); proxyType.Assembly.IsDynamic.ShouldBeTrue(); var properties = proxyType.GetProperties(); properties.ShouldContain(p => p.Name == "Name"); properties.ShouldContain(p => p.Name == "Description"); properties.ShouldNotContain(p => p.Name == nameof(IHasFormFieldsList._formFields)); proxyType.ShouldNotBeAssignableTo(typeof(IHasFormFieldsList)); var supervisorProp = properties.FirstOrDefault(p => p.Name == supervisorPropName); supervisorProp.ShouldNotBeNull($"{supervisorPropName} property is missing in the created DTO"); // nested object should be dynamic supervisorProp.PropertyType.Assembly.IsDynamic.ShouldBeTrue(); typeof(IDynamicNestedObject).IsAssignableFrom(supervisorProp.PropertyType).ShouldBeTrue($"Dynamic nested object must implement {nameof(IDynamicNestedObject)}"); var nestedProperties = supervisorProp.PropertyType.GetProperties(); nestedProperties.ShouldContain(p => p.Name == supervisorFirstNamePropName); nestedProperties.ShouldContain(p => p.Name == supervisorLastNamePropName); }
/// <summary> /// Returns .Net type that is used to store data for the specified DTO property (according to the property settings) /// </summary> public async Task <Type> GetDtoPropertyTypeAsync(EntityPropertyDto propertyDto, DynamicDtoTypeBuildingContext context) { var dataType = propertyDto.DataType; var dataFormat = propertyDto.DataFormat; switch (dataType) { case DataTypes.Guid: return(typeof(Guid?)); case DataTypes.String: return(typeof(string)); case DataTypes.Date: case DataTypes.DateTime: return(typeof(DateTime?)); case DataTypes.Time: return(typeof(TimeSpan?)); case DataTypes.Boolean: return(typeof(bool?)); case DataTypes.ReferenceListItem: // todo: find a way to check an entity property // if it's declared as an enum - get base type of this enum // if it's declared as int/Int64 - use this type return(typeof(Int64?)); case DataTypes.Number: { switch (dataFormat) { case NumberFormats.Int32: return(typeof(int?)); case NumberFormats.Int64: return(typeof(Int64?)); case NumberFormats.Float: return(typeof(float?)); case NumberFormats.Double: return(typeof(decimal?)); default: return(typeof(decimal?)); } } case DataTypes.EntityReference: return(GetEntityReferenceType(propertyDto, context)); case DataTypes.Array: { if (propertyDto.ItemsType == null) { return(null); } var nestedType = await GetDtoPropertyTypeAsync(propertyDto.ItemsType, context); var arrayType = typeof(List <>).MakeGenericType(nestedType); return(arrayType); } case DataTypes.Object: return(await BuildNestedTypeAsync(propertyDto, context)); // JSON content default: throw new NotSupportedException($"Data type not supported: {dataType}"); } }