Reputation: 60821
How do we avoid breaking changes in a controller method, when the database schema changes?
Suppose I am returning an object:
public class Bike
{
public int Wheels {get;}
public int Id {get;}
}
in the following controller:
public class BikeController
{
[HttpGet]
public List<Bike> Get([FromBody] MyRequest request)
{
var context = new DbContext(_repository.Database.Connection.ConnectionString);
var procedure = request;
return context.Database.ExecuteStoredProcedure<Bike>(procedure).ToList();
}
}
At some point, the database code changes. I don't want to have to redefine the Bike schema in C#.
How do we change the signature of the Bike controller method, in order to not have any breaking changes, when the database schema changes?
I'm looking for something like the following:
public IHttpActionResult Get()
{
var context = new DbContext(_repository.Database.Connection.ConnectionString);
var procedure = request;
return context.Database.ExecuteStoredProcedure<object>(procedure).ToList();
}
Upvotes: 1
Views: 264
Reputation: 1455
As long as you don't access any property or use any method its existence is dependent on a schema object or anything related to the database You are on the safe side.
Making the controller agnostic to the database schema, will make it very unlikely that this controller will be changed due to changes on the database side, and that's why the Data Access layers
are made.
I think if we applied separation of concerns principle we would see that it is not the Controller
responsibility to deal with the database, this must be done through some kinds of Brokers
like a repository interface type injected into the controller constructor. The controller will just see insert, update, delete methods but it doesn't have any knowledge about the database.
Also, it's not a loosely-typed object. It's a loosely coupled types what you really need.
Upvotes: 1
Reputation: 1691
You are simply retrieving an object from the database, the number of properties which comes inside the object wont effect or break your ActionMethod.
If you are still worried for a reason like the properties inside your object are not what you want to render on the view then you can use a ViewModel and use your Bike objects properties to populate the viewmodel and render the viewmodel instead.
Upvotes: 1
Reputation: 77896
I don't see why your controller at all need to change since you are just returning the retrieved type directly without referring any of it's properties in your action method.
Moreover, why you are calling .ToList()
when you are returning a single Bike
object. Further more, you may consider using a Model or ViewModel instead of returning the entity directly as an option.
@Evk already pointed that a newly added property would just get lost while deserializing but if you want to return a abstract object then you can have all your entity inherits from a BaseEntity
having common property and return that instead like
BaseEntity obj = context.Database.ExecuteStoredProcedure<Bike>(procedure);
returb obj;
Upvotes: 3
Reputation: 26926
I think you have a few alternatives:
Return dynamic
instead of Bike
. However, this has a performance impact on all users of the dynamic
objects.
Return object
instead of Bike
.
But in both cases your Bike stored procedure will still return the updated data which won't be compatible with the Bike
object, so you will still need to recompile the controller.
BikeController
response and matches the stored procedures response.Consider how you handle database updates in SQL - your SELECT statement specifies the exact columns you need and is unaffected by schema changes that don't affect the returned columns, or if you are using *
you ignore any columns you don't need, which isn't conducive to strong typing or ORMs.
Upvotes: 1