7 Replies - 689 Views - Last Post: 04 March 2020 - 02:25 AM

#1 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6834
  • View blog
  • Posts: 28,372
  • Joined: 12-December 12

log changes, map EF fields

Posted 02 March 2020 - 02:06 AM

[ASP.NET MVC and Entity Framework]

I have a Jobs Service and, depending on a setting, saving a job will write to a Job Actions log, e.g. "Worker changed from Fred to Bob", "Status changed from Accepted to Active".

However, Worker, Status, etc., can also be changed from 10 other modules, and these changes also need to be logged.

Currently, for each module and each method (ChangeWorker), I am modifying the:
controller to call ChangeWorker, then call log changes - a method WriteChangesDirect in the JobActions service;
service and repo method, ChangeWorker, not only to do the change but also (if needed) to return a list of change details

Because logging occurs across 23 values/fields this is going to be a big messy task, with a lot of repetition.

What I am considering instead is to leave the update methods "as-is" but to modify just the service methods. Instead of

        public DataContextResult<List<JobActionDetail>> ChangeJobsWorker(string jobIds, string workerId)
        {
            return _worksDiaryRepository.ChangeJobsWorker(jobIds, workerId);
        }


        public DataContextResult<List<JobActionDetail>> ChangeJobsWorker(string jobIds, string workerId)
        {
            If (autoStoreJobActions) 
                PMJobsService.GetListOfValues(jobIds, “Worker”);    // or use reflection (or an enum/constants?) to identify the field
                // should this return the field id’s or probably go and get the string values we need at this stage?
            return _worksDiaryRepository.ChangeJobsWorker(jobIds, workerId);
            
            If (autoStoreJobActions)
                PMJobActionsService.WriteJobActionsDirect(List<JobActionDetails> foo, string newValue, int userId);

            // this write method could construct the full message because it is the same each time “Thing changed from x to y”.
        }



My issue is that the fields being changed are generally integer values, and their textual representation needs to be obtained from a different table, with a different field name. Note that the database is very poorly designed with limited use of configured foreign fields. We cannot change the design currently.

So my proposed method GetListOfValues will need, somehow, to map CurrentStatus in the jobs table to UID and Status in the PMStatusLevels table. Do the same for circa. 20 other field names/tables.

[There is a generic repository level as well which we don't want to touch.]

How might you approach this while maintaining some level of a "proper" flexible pattern? That is, to map 20 field names to other field name/ tables.

Reflection?
Enums/ constants?
A big switch statement with specific reference to field and table names? This is what we hope to avoid.
Is it possible with EF to somehow to create a 'model' that maps field names (from one table) to field names of other tables? Perhaps by adding some 'faux' foreign keys/ relations?

Is This A Good Question/Topic? 0
  • +

Replies To: log changes, map EF fields

#2 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6834
  • View blog
  • Posts: 28,372
  • Joined: 12-December 12

Re: log changes, map EF fields

Posted 02 March 2020 - 02:51 AM

I should clarify that the updating of worker, etc., does not occur centrally in the PMJobs service, only the initial Save of a job does this. Each area/module has its own methods ChangeWorker, ChangeStatus, etc.
Was This Post Helpful? 0
  • +
  • -

#3 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7291
  • View blog
  • Posts: 24,675
  • Joined: 05-May 12

Re: log changes, map EF fields

Posted 02 March 2020 - 04:25 PM

Automapper or Dapper perhaps?

Is there away you can have all your different modules share a common data access layer (that is self-consistent either by running as a single process or is communicating across multiple processes using REDIS)?

Or perhaps instead of logging from the controller or the data model, let the database itself trigger an event when the data changed? E.g. Log after the fact instead of before/during the change.
Was This Post Helpful? 2
  • +
  • -

#4 Sheepings   User is offline

  • D.I.C Lover
  • member icon

Reputation: 237
  • View blog
  • Posts: 1,282
  • Joined: 05-December 13

Re: log changes, map EF fields

Posted 02 March 2020 - 06:34 PM

Just a side note regarding EF. If you have the authority to change your ORM to something more efficient and stable, other than Entity Framework, you would be saving yourself a lot of unnecessary hassle and headaches down the line. Not only is Entity Framework ridiculously shit. Its also riddled with bugs, and suffers terrible with memory leaks. These bugs have never been fixed to-date as far as I am aware. Dapper would be the way I would go too especially if I was required to use a ORM like EF. The last time I used EF at work, I nearly blew my brains out. Thankfully my new employers have brains and use Dapper too.
Was This Post Helpful? 2
  • +
  • -

#5 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6834
  • View blog
  • Posts: 28,372
  • Joined: 12-December 12

Re: log changes, map EF fields

Posted 03 March 2020 - 05:00 AM

Thank you both.

We won't be changing from EF but I will investigate AutoMapper (which we have) to see if there is anything I can do with it.
Was This Post Helpful? 0
  • +
  • -

#6 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6834
  • View blog
  • Posts: 28,372
  • Joined: 12-December 12

Re: log changes, map EF fields

Posted 03 March 2020 - 07:33 AM

I have been wrestling with generic methods and AutoMapper features but, for the moment, have accepted a reasonable compromise.

I am creating 23 methods in the JobsService e.g. GetCurrentStatuses, GetCurrentWorkers. Then in the other module's service layers I am using code similar to that outlined in my OP.

        public DataContextResult<string> ChangeWorker(int workerId, List<int> ppmIds, List<int> jobIds = null, bool startDateChanged = false)
        {

            bool autoStoreJobActions = GlobalSettings<PMSettings>.Data.AutoStoreJobActions;
            DataContextResult<List<JobActionDetail>> jobActionDetails = null;

            if (autoStoreJobActions)
            {
                jobActionDetails = _pmJobsService.GetCurrentWorkers(jobIds, workerId);
            }

            var result = _pmPPMGroupsRepo.ChangeWorker(workerId, ppmIds, jobIds, startDateChanged);

            if (result.Success && autoStoreJobActions)
            {
                UserSettings userSettings = (UserSettings)System.Web.HttpContext.Current.Session["UserSettings"];
                int userId = userSettings.UserProfiles.UID;

                var jobActionsResult = _pmJobActionsService.WriteJobActionsDirect(jobActionDetails.Result, userId, "Worker");
            }

            return result;
        }

That is, I wrap calls to GetCurrentWorkers and WriteJobActionsDirect around the original call to ChangeWorker.

This is in part necessitated because, for example, GetStartDatesAndTimes is very different to GetCurrentWorkers.

This has the benefit that I have no need to modify the original save methods (ChangeWorker, etc.), nor their related interfaces.

I think it also means that if, at some point, someone has inspiration to make some generic method to collect the existing values (be they Status, Worker) these individual methods are all located at a single point (the Jobs repo, essentially).
Was This Post Helpful? 0
  • +
  • -

#7 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7291
  • View blog
  • Posts: 24,675
  • Joined: 05-May 12

Re: log changes, map EF fields

Posted 03 March 2020 - 11:05 AM

Part of me feels like an opportunity for a Decorator pattern is being missed here...

Admittedly, though, implementing the decorator pattern will likely result in even more typing (probably 2-3 times more typing), and the main thrust of the original question was to figure out how to minimize the amount of typing needed to implement the required logging.
Was This Post Helpful? 1
  • +
  • -

#8 andrewsw   User is offline

  • never lube your breaks
  • member icon

Reputation: 6834
  • View blog
  • Posts: 28,372
  • Joined: 12-December 12

Re: log changes, map EF fields

Posted 04 March 2020 - 02:25 AM

Thanks Skydiver.

I'll review the Decorator pattern. Something like this was shouting out to me as well. I recall in Core, more so than ASP.NET MVC I believe, we could add "filters" to the pipeline, or something similar. (We are not keen on database triggers.)

I would rather decry the notion of 'reduced typing' in favour of DRY principles ;)/>. Also finding the correct location to place code so that there is the least impact - extending rather than modifying. I wanted the current Update process and methods to work as-is, but to extend (or decorate) the process to write logs.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1