I know most (if not all) business logic should reside in its own layer, but what is the general consensus of putting some basic business logic inside of the repository layer itself?
My scenario:
We have a table that has a few optional columns, but should one of the columns contain a value, the other two will be influenced by that value.
A POCO of an entity for that table looks something like:
public class Template
{
public int Id {get;set;}
public string MessageTemplate {get;set;}
public int? FacilityId {get;set;}
public int? ResourceId {get;set;}
public bit GlobalDefault {get;set;}
}
Now there should only be one entry that is designated as the global default, and similarly, each facility or resource should only be listed in the table once. The latter constraints are enforced by SQL Server, but this does require some business logic to make sure everything flows smoothly.
In this table's case, should we attempt to insert a new record for an existing facility or resource, the previous record should either be updated instead (or deleted). The same is true for setting a new global default. Only one entity should be the global default so if another exists it should either be deleted or updated instead.
Now obviously, my business layer is going to handle these scenarios to the best of their ability, but how frowned upon is it to also implement that level of logic in my repositories themselves?
I'm envisioning something like the following in my repo:
public void InsertFacilityTemplate(Template template)
{
var existing = context.Templates.Where(n => n.FacilityId == template.FacilityId);
Template recordToSave;
if (existing.Count > 1)
DeleteRecords(existing);
if (existing.Count == 1)
recordToSave= existing.First();
if (recordToSave != null)
{
recordToSave.MessageTemplate = template.MessageTemplate;
Update(recordToSave);
}
else
Insert(template);
}
What is the proper approach here?
Best Answer
Databases and methods often use the term upsert for actions that either insert OR update based on existence. It's fine to have an upsert method in a repository.
It's not clear from you description if you are asking about repeating the insert/update logic elsewhere, or you are asking where to put this logic (i.e. example method).
RemoveDuplicateInstances(ITemplate template)
orPrepareUpsert(string templateId)
. The example also assumes to know what the updated field is. For example, if the GlobalDefault value was toggled, or another field was added to the class then the Insert would preserve those changes while the logic to the Update wouldn't. That would be inconsistent behavior with the expectation.Those concerns being said, if your application is small, proof-of-concept, or exceedingly simple then these change are going to be so minor that it won't functionally make a difference. It will make a difference if someone else is coming after you or the intention is to continue expanding this code base.