Let's start with a master dynamic content, or status = 0 in sf_dynamic_content, and call it production.
Let's say its current approval_workflow_State_ = "Published", and visible = 0 (it will always be 0 because you never see the master). We should, less ye have been hacking around in the system, have another record in this table with same url_name_ and approval_workflow_State_ = "Published", status= 2, and visible = 1. That will be the Live version.
var dynamicModuleManager = DynamicModuleManager.GetManager();<
>var checkedOutProduction = (DynamicContent) dynamicModuleManager.Lifecycle.CheckOut(production);
These lines will let us to edit the master, but it doesn't give us the live version, just a temp version you can modify a bit. Honestly I don't see the point of using it unless you are worried about concurrency or other issues that could exist. What I mean here is that you can make edits directly on the master record, but bear in mind if dynamicModuleManager.SaveChanges() somewhere else in the code concurrently, I believe your changes will be collected and persisted. I don't really know exactly how they are doing this, but OpenAccess system is very similar to older ORM system that don't use poco objects and it doesn't manually have you declare what you want to save, meaning something like this dynamicModuleManager.SaveChanges(production). Therefor the check-in and check-out pattern.
this line just sets the master to unpublished, making approval_workflow_State_ = "Unpublished".
var checkedInProduction = (DynamicContent) dynamicModuleManager.Lifecycle.CheckIn(checkedOutProduction);
These lines check in the temp, replacing the existing master record (in memory). Any calls to dynamicModuleManager.SaveChanges() will now persist the changes.
Now for the important code:
var liveProduction = dynamicModuleManager.Lifecycle.GetLive(checkedInProduction);
This will change visible = 0 but keeps approval_workflow_State_ = "Published". This is what you want. If you don't believe me, interact with a dynamic content type from its list view page. Look at the 2 records for an item in the database before and after selecting it for unpublishing.
Now you have persisted your changes.
A side note: if you are trying to unpublish an item with no Live version, like a draft that have never been published, you'll notice there is only 1 record in the database. The code above checks for that by verifying that live version is not null. If if is, technically you are breaking the workflow and it shouldn't be a valid operation. What I would do here, is verify that your master record has approval_workflow_State_ = "Published" before doing any of this this, even before you check it out, because you don't really want to set your master record to unpublished from the draft state.