Supposing I have a model:
public class Thing
{
public int? identifier { get; set; }
public string Title { get; set; }
public string Description { get; set; }
... // arbitrary number of additional properties.
}
And an interface to a service layer containing two key methods:
public interface IThingService
{
Thing GetThing(int id);
Thing AddThing(Thing thing);
}
Now, suppose the service layer will automatically generate an identifier for each thing upon AddThing. Also suppose that it is important to expose this identifier to the presentation layer as it may be passed to other services.
Given that I must pass a Thing to AddThing, is this the best way of modelling Thing? The developer of the presentation layer may think that they can specify an identifer, but this will be ignored by the concrete implementation of IThingService. Of course, identifier must be public to be set by IThingService for GetThing.
Is it okay to simply ignore an identifier passed in a call to AddThing, or is there a better way to model this to prevent that from happening?
Your service should look something like this:
public interface IThingService
{
Thing GetThing(int id);
ThingCreationResponse AddThing(ThingCreationRequest request);
}
ThingCreationRequest would have all the necessary data to create a Thing entity. It would not have an identifier. Identifier would be returned by AddThing.
AddThing could simply return a Thing id, but in that case you should provide a well documented protocol to communicate errors (returning a negative value in case of a failure, or throw an exception).
Returning an instance of the ThingCreationResponse would provide you a better flexibility since you can return an id or a complete instance of the new Thing, also failure reasons could be communicated better.
This will only work if the service is operating on the same memory that the original Thing actually lives on. If this service is disconnected, say on a different machine for instance, then updating the Thing will not affect the original instance and the identifier will never be returned to the calling code.
With that in mind, there are 2 possible paths: you intend for this service to always be local and operating on the same memory as the calling application, or you intend for this service to actual be or eventually become disconnected.
If it's connected, this interface will work fine, but you might still want to hide the setter for the identifier. If you do, you can just make it internal and define both the service interface and the Thing object in a separate assembly, which will make the setter inaccessible to the presentation layer. Well almost, you could still invoke it with reflection or other hijinks, but for typical stuff it will be inaccessible.
This interface is just broken because you cannot retrieve the identifier in any way, and it is necessary in order to retrieve the now saved item back. Typical solutions here would return the identifier from the AddThing method or the entire object (new memory) if it's small enough.
Aside from all of this, immutable data items are difficult to reason about, and in either case I'd probably prefer to create a new Thing after calling AddThing anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With