public object CreateEntityAndFillFromDto(TDto dto, string methodCtorName) { if (!_entityInfo.CanBeCreatedByCtorOrStaticMethod && !_entityInfo.CanBeCreatedViaAutoMapper) { throw new InvalidOperationException($"I cannot create the entity class {_entityInfo.EntityType.Name} because it has no public constructor, or valid static creator methods."); } //we look for methods to create/update a new entity in the following order //1. A public static method that returns IStatusGeneric (chosing the one with the most parameters that the DTO has too) //2. A public parameterised constructor (chosing the one with the most parameters that the DTO has too) //3. By creating via parameterless ctor and then using AutoMapper to set the properties var decodedName = _dtoInfo.GetSpecifiedName(methodCtorName, CrudTypes.Create); if (_entityInfo.CanBeCreatedByCtorOrStaticMethod) { var ctorStaticToRun = _dtoInfo.GetCtorStaticCreatorToRun(decodedName, _entityInfo); var runStatus = BuildCall.RunMethodOrCtorViaLinq(ctorStaticToRun, dto, ctorStaticToRun.PropertiesMatch.MatchedPropertiesInOrder.ToList(), _context); CombineStatuses(runStatus); return(runStatus.Result); } if (_entityInfo.HasPublicParameterlessCtor && _entityInfo.CanBeUpdatedViaProperties) { var entityInstance = Activator.CreateInstance(_entityInfo.EntityType); var mapper = new CreateMapper(_context, _wrapperMapperConfigs, typeof(TDto), _entityInfo); mapper.Accessor.MapDtoToEntity(dto, entityInstance); return(entityInstance); } throw new InvalidOperationException( $"There was no way to create the entity class {_entityInfo.EntityType.Name} using {decodedName.ToString() ?? "any approach"}."); }
public void TestBuildCallMethodNoReturnWithDbContext() { //SETUP var options = SqliteInMemory.CreateOptions <TestDbContext>(); using (var context = new TestDbContext(options)) { context.Database.EnsureCreated(); var prop1 = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, typeof(Dto).GetProperty(nameof(Dto.MyInt))); var prop2 = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, null, MatchSources.DbContext, context.GetType()); var method = typeof(Target1).GetMethod(nameof(Target1.SetMyIntAndAddEntityToDb)); var dto = new Dto { MyInt = 123 }; var target = new Target1(); //ATTEMPT var action = BuildCall.CallMethodReturnVoid(method, typeof(Dto), typeof(Target1), new List <PropertyMatch> { prop1, prop2 }); action.Invoke(dto, target, context); context.SaveChanges(); //VERIFY target.MyInt.ShouldEqual(123); context.NormalEntities.Count().ShouldEqual(1); } }
/// <summary> /// This look for methods to update a new entity in the following order /// 1. DDD-styled entity: A public access method that fits the DTO /// 2. Standard styled entity: using AutoMapper to update the entity</summary> /// <param name="dto"></param> /// <param name="methodName"></param> /// <param name="entity"></param> /// <param name="mapper"></param> /// <returns></returns> private IStatusGeneric RunMethodViaLinq(TDto dto, string methodName, dynamic entity, CreateMapper mapper) { var decodedName = _dtoInfo.GetSpecifiedName(methodName, CrudTypes.Update); if (_entityInfo.CanBeUpdatedViaMethods && decodedName.NameType != DecodedNameTypes.AutoMapper) { //1. DDD-styled entity: A public access method that fits the DTO //This gets one method to run. If it can't be found, or there are too many matches it throws an exception var methodToUse = _dtoInfo.GetMethodToRun(decodedName, _entityInfo); //This runs the method via LINQ return(BuildCall.RunMethodViaLinq(methodToUse.Method, dto, entity, methodToUse.PropertiesMatch.MatchedPropertiesInOrder.ToList(), _context)); } if (_entityInfo.CanBeUpdatedViaProperties) { //2. Standard styled entity: using AutoMapper to update the entity mapper.Accessor.MapDtoToEntity(dto, entity); return(new StatusGenericHandler()); } throw new InvalidOperationException( $"There was no way to update the entity class {_entityInfo.EntityType.Name} using {decodedName.ToString() ?? "any approach"}."); }
public void TestBuildCallNoParameters() { //SETUP var method = typeof(Book).GetMethod(nameof(Book.RemovePromotion)); var target = DddEfTestData.CreateFourBooks().Last(); //ATTEMPT var action = BuildCall.CallMethodReturnVoid(method, typeof(Tests.Dtos.ChangePubDateDto), typeof(Book), new List<PropertyMatch>()); action.Invoke(target); //VERIFY target.ActualPrice.ShouldEqual(target.OrgPrice); }
public void TestBuildCallMethodNoReturnAgain() { //SETUP var prop = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, typeof(Dto).GetProperty(nameof(Dto.MyInt))); var method = typeof(Target1).GetMethod(nameof(Target1.SetMyInt)); var dto = new Dto { MyInt = 123 }; var target = new Target1(); //ATTEMPT var action = BuildCall.CallMethodReturnVoid(method, typeof(Dto), typeof(Target1), new List<PropertyMatch>{prop}); action.Invoke(dto, target); //VERIFY target.MyInt.ShouldEqual(123); }
public void TestBuildCallCtor() { //SETUP var prop1 = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, typeof(Dto).GetProperty(nameof(Dto.MyInt))); var prop2 = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, typeof(Dto).GetProperty(nameof(Dto.MyString))); var ctor = typeof(Target1).GetConstructors().Single(x => x.GetParameters().Length == 2); var dto = new Dto { MyInt = 123, MyString = "Hello" }; //ATTEMPT var func = BuildCall.CallConstructor(ctor, typeof(Dto), new List<PropertyMatch> { prop1, prop2 }); var newInstance = func.Invoke(dto); //VERIFY ((int)newInstance.MyInt).ShouldEqual(123); ((string)newInstance.MyString).ShouldEqual("Hello"); }
public void TestBuildCallMethodWithReturn() { //SETUP var prop = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, typeof(Dto).GetProperty(nameof(Dto.MyString))); var method = typeof(Target1).GetMethod(nameof(Target1.SetMyString)); var dto = new Dto { MyString = "Hello" }; var target = new Target1(); //ATTEMPT var action = BuildCall.CallMethodReturnStatus(method, typeof(Dto), typeof(Target1), new List<PropertyMatch> {prop}); var status = action.Invoke(dto, target); //VERIFY target.MyString.ShouldEqual("Hello"); ((string)status.Message).ShouldEqual("OK"); }
public void TestBuildCallChangePubDateDto() { //SETUP var prop = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, typeof(Tests.Dtos.ChangePubDateDto).GetProperty(nameof(Tests.Dtos.ChangePubDateDto.PublishedOn))); var method = typeof(Book).GetMethod(nameof(Book.UpdatePublishedOn)); var dto = new Tests.Dtos.ChangePubDateDto { PublishedOn = new DateTime(2000,1,1)}; var target = DddEfTestData.CreateDummyBooks(1).Single(); //ATTEMPT var action = BuildCall.CallMethodReturnVoid(method, typeof(Tests.Dtos.ChangePubDateDto), typeof(Book), new List<PropertyMatch>{prop}); action.Invoke(dto, target); //VERIFY target.PublishedOn.ShouldEqual(new DateTime(2000, 1, 1)); }
public void TestBuildCallStatic() { //SETUP var prop1 = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, typeof(Dto).GetProperty(nameof(Dto.MyInt))); var prop2 = new PropertyMatch(true, PropertyMatch.TypeMatchLevels.Match, typeof(Dto).GetProperty(nameof(Dto.MyString))); var method = typeof(Target1).GetMethod(nameof(Target1.Create)); var dto = new Dto { MyInt = 123, MyString = "Hello" }; //ATTEMPT var action = BuildCall.CallStaticCreator(method, typeof(Dto), new List<PropertyMatch> { prop1, prop2}); var status = action.Invoke(dto); //VERIFY ((string)status.Message).ShouldEqual("Static"); ((int)status.Result.MyInt).ShouldEqual(123); ((string)status.Result.MyString).ShouldEqual("Hello"); }
public IStatusGeneric ReadEntityAndUpdateViaDto(TDto dto, string methodName, params Expression <Func <TDto, object> >[] includes) { //first we need to load it var keys = _context.GetKeysFromDtoInCorrectOrder(dto, _dtoInfo); var mapper = new CreateMapper(_context, _configAndMapper, typeof(TDto), _entityInfo); var entity = mapper.Accessor.ReturnExistingEntity(keys, includes); if (entity == null) { return(new StatusGenericHandler() .AddError( $"Sorry, I could not find the {_entityInfo.EntityType.GetNameForClass()} you were trying to update.")); } //we look for methods to update a new entity in the following order //1. DDD-styled entity: A public access method that fits the DTO //2. Standard styled entity: using AutoMapper to update the entity var decodedName = _dtoInfo.GetSpecifiedName(methodName, CrudTypes.Update); if (_entityInfo.CanBeUpdatedViaMethods && decodedName.NameType != DecodedNameTypes.AutoMapper) { //1. DDD-styled entity: A public access method that fits the DTO //This gets one method to run. If it can't be found, or there are too many matches it throws an exception var methodToUse = _dtoInfo.GetMethodToRun(decodedName, _entityInfo); //This runs the method via LINQ return(BuildCall.RunMethodViaLinq(methodToUse.Method, dto, entity, methodToUse.PropertiesMatch.MatchedPropertiesInOrder.ToList(), _context, _createNewDBContext)); } if (_entityInfo.CanBeUpdatedViaProperties) { //2. Standard styled entity: using AutoMapper to update the entity mapper.Accessor.MapDtoToEntity(dto, entity); return(new StatusGenericHandler()); } throw new InvalidOperationException( $"There was no way to update the entity class {_entityInfo.EntityType.Name} using {decodedName.ToString() ?? "any approach"}."); }