0

I have MyWizardDto which I use to transfer Dto objects between different layers. The Dto objects can be any number of objects. MyWizardDto is used in MyWizardAppService to insert records for each entity into the database. In MyWizardAppService I would know in advance the super set of repositories that may be required, currently I have added two for demonstration purposes but these can increase, and if any Dto object is null then we don't need to map or call its repository method for interacting with the database.

In MyWizardAppService.CreateOrUpdate method, I can hardwire multiple if/else statements to first map each Dto (ClientDto, ContactDto) to its corresponding entity (Client, Contact) using Automapper and then call the corresponding repository (_clientRepository, _contactRepository) to add/update record into the database. However, I am wondering if I can use reflection or some other method to avoid multiple if/else statements as number of entities can increase. I will always know the superset in advance so all relevant repositories will be injected in the same way as the current two repositories.

Is it possible to change my MyWizardAppService.CreateOrUpdate method to accomplish my objective without using multiple if/else statements? I am following the same naming convention e.g ClientDto, Client and _clientRepository so I don't know if that can be of help for using as rule of thumb.

public class MyWizardDto
    {
        public ClientDto client { get; set; }
        public ContactDto contact { get; set; }                        
    }
public class ClientDto  
    {              
        public string Forename { get; set; }       
        public string Surname { get; set; }        
        public DateTime? DateOfBirth { get; set; }
    }
public class ContactDto  
    {              
        public string Street { get; set; }       
        public string City{ get; set; }        
    }
public class Client
    {              
        public string Forename { get; set; }       
        public string Surname { get; set; }        
        public DateTime? DateOfBirth { get; set; }
    }
public class Contact  
    {              
        public string Street { get; set; }       
        public string City{ get; set; }        
    }
public interface IMyWizardAppService
    {        
        Task<ResponseOutputDto> CreateOrUpdate(MyWizardDto myWizardDto);        
    }
public class ResponseOutputDto
    {
        public bool IsSuccess { get; set; }
        public string Message { get; set; }
    }
public class MyWizardAppService
    {
        private readonly IRepository<Client> _clientRepository;
        private readonly IRepository<Contact> _contactRepository;
// there can be more repository entities
        private ResponseOutputDto responseOutputDto;

        public MyWizardAppService(           
             IRepository<Client> clientRepository,
             IRepository<Contact> contactRepository)           
        {            
            _clientRepository = clientRepository;
            _contactRepository = contactRepository;
            responseOutputDto = new ResponseOutputDto();
        }
        public async Task<ResponseOutputDto> CreateOrUpdate(MyWizardDto myWizardDto)
        {
            PropertyInfo[] properties = myWizardDto.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                string temp = property.Name;
// to check if property is dto object and is not null
// if not null then map dto to its corresponding object e.g ClientDto to Client,
//I am using AutoMapper  e.g ObjectMapper.Map<Client>(myWizardDto.client);
// now call corresponding entities repository e.g if ClientDto then call
// _clientRepository's insert.


            }

            //if no error return success
            responseOutputDto.IsSuccess = true;
            return responseOutputDto;
        }

    }

As suggested by @Unknown I changed the MyWizardAppService as shown below but now I get compile time error: Client / IRepository is a type which is not valid in the given context

public class MyWizardAppService
    {
        private readonly IRepository<Client> _clientRepository;
        private readonly IRepository<Contact> _contactRepository;
        private Dictionary<Type, IRepository> _repositoryPairs;
// there can be more repository entities
        private ResponseOutputDto responseOutputDto;

        public MyWizardAppService(           
             IRepository<Client> clientRepository,
             IRepository<Contact> contactRepository)           
        {            
            _clientRepository = clientRepository;
            _contactRepository = contactRepository;
            responseOutputDto = new ResponseOutputDto();

_repositoryPairs = new Dictionary<Type, IRepository>(); 
//GET ERROR ON FOLLOWING LINE
_repositoryPairs.Add(<Client>, IRepository<Client>);
        }
        public async Task<ResponseOutputDto> CreateOrUpdate(MyWizardDto myWizardDto)
        {
            PropertyInfo[] properties = myWizardDto.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                string temp = property.Name;
// to check if property is dto object and is not null
// if not null then map dto to its corresponding object e.g ClientDto to Client,
//I am using AutoMapper  e.g ObjectMapper.Map<Client>(myWizardDto.client);
// now call corresponding entities repository e.g if ClientDto then call
// _clientRepository's insert.


            }

            //if no error return success
            responseOutputDto.IsSuccess = true;
            return responseOutputDto;
        }

    }

Update 2 I now get error on TryGet it says Disctionary does not contain a definition for TryGet.

public class MyWizardAppService
    {
        private readonly IRepository<Client> _clientRepository;
        private readonly IRepository<Contact> _contactRepository;
        private Dictionary<Type, IRepository> _repositoryPairs;
// there can be more repository entities
        private ResponseOutputDto responseOutputDto;

        public MyWizardAppService(           
             IRepository<Client> clientRepository,
             IRepository<Contact> contactRepository)           
        {            
            _clientRepository = clientRepository;
            _contactRepository = contactRepository;
            responseOutputDto = new ResponseOutputDto();

_repositoryPairs = new Dictionary<Type, IRepository>(); 
_repositoryPairs.Add(typeOf(Client), _clientRepository);
        }
        public async Task<ResponseOutputDto> CreateOrUpdate(MyWizardDto myWizardDto)
        {
            PropertyInfo[] properties = myWizardDto.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                string temp = property.Name;

                IRepository repo;                
                if (_repositoryPairs.TryGet(property.GetType(), out repo))
                {
                    //call insert here some how
                }  



// to check if property is dto object and is not null
// if not null then map dto to its corresponding object e.g ClientDto to Client,
//I am using AutoMapper  e.g ObjectMapper.Map<Client>(myWizardDto.client);
// now call corresponding entities repository e.g if ClientDto then call
// _clientRepository's insert.


            }

            //if no error return success
            responseOutputDto.IsSuccess = true;
            return responseOutputDto;
        }

    }

learner
  • 581
  • 7
  • 27
  • 1
    Of course you would get an error. `` is not valid C#. That was a place holder in the answer and you were supposed to substitute it with an actual type. I am guessing `typeof(Client)` here. – Tanveer Badar Feb 04 '20 at 18:28
  • 1
    `...Add(.., IRespository)` also won't work - you have to actually create a repository to add. – Michael Jones Feb 04 '20 at 18:34
  • i have changed it and error is not appearing. However, I now get error on TryGet, also I don't know what to pass in TryGet, see update 2, I have tried property.GetType() but that doesn't seem right. – learner Feb 04 '20 at 18:55
  • @learner - 1) Its actually `TryGetValue()` method. 2)Regarding the first parameter, you have to pass in the entity's` type` Since Entity's type is used as the key for registering the repositories in dictionary. 3) Regarding angle bracket inside `Add()` method, the sample code in my answer is just like a pseudo-code with placeholder. It indicates that you have to replace the entire section including with your code. – Unknown Feb 05 '20 at 03:57
  • @learner - Move `_repositoryPairs.TryGetValue` method out of foreach method. After mapping DTO to corresponding entity, pass in the entity's type `typeof(mappedEntity)` as the first parameter to the `TryGetValue()` method. – Unknown Feb 05 '20 at 04:04
  • You need to learn C# from a good source. The keyword is `typeof`, not `typeOf` in your updated code. – Tanveer Badar Feb 05 '20 at 18:00

1 Answers1

0

Am not sure if this answers your question. If not, just take it as a hint.

For removing multiple if-else statements for Mapping Dto to Corresponding Model, you can refer this post.

For removing multiple if-else statements for calling appropriate repository, simply have a Dictionary<Type,Repository> and pre-initialize it with all the repositories like this.

//Just a sample code, not actual one.
repoDictionary.Add(<ClientModelType>,<ClientRepositoryInstance>);
repoDictionary.Add(<ContactModelType>,<ContactRepositoryInstance>);

Then instead of using conditional statements, you can simply query the repository dictionary to perform DB operations like this.

//Just a sample code, not actual one.
Repository repo;
if(repoDictionary.TryGetValue(model.GetType(), out repo)){
  repo.CallRequiredMethod(model);
}

Hope this might help you in some way.

Unknown
  • 531
  • 5
  • 18
  • I am getting error when I used Dictionary _repositoryPairs;_repositoryPairs = new Dictionary(); _repositoryPairs.Add(, IRepository); – learner Feb 04 '20 at 15:37
  • Error for both parameters: Client / IRepository is a type which is not valid in the given context. I am initializing dictionary in the constructor of MyWizardAppService. – learner Feb 04 '20 at 15:39
  • 1
    Could you pls post the new code so that it will be easier to debug – Unknown Feb 04 '20 at 17:15
  • I have updated my question with the new code. The only change I made is declared Dictionary and then tried to initialise it in the constructor of MyWizardAppService. – learner Feb 04 '20 at 18:27
  • Added comments in the question. Please look there. – Unknown Feb 05 '20 at 04:06