Generated Code-DB alignment

Posts   
 
    
Valemus avatar
Valemus
User
Posts: 37
Joined: 09-Jan-2018
# Posted on: 05-Jul-2018 10:38:34   

Hello!

Is there a way to automatically check if the generated code is aligned with a connected DB structure?

Or is there a way to automatically add to the generated code a DateTime or a version number every time the code is generated?

Thanks!

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 05-Jul-2018 20:11:11   

is there a way to automatically add to the generated code a DateTime

Please set the following project setting to true: Project Settings / Conventions / Entity Model / LLBLGen Pro Runtime Framework / General / tdl emit time date in output files

Valemus avatar
Valemus
User
Posts: 37
Joined: 09-Jan-2018
# Posted on: 06-Jul-2018 09:07:27   

Walaa wrote:

is there a way to automatically add to the generated code a DateTime

Please set the following project setting to true: Project Settings / Conventions / Entity Model / LLBLGen Pro Runtime Framework / General / tdl emit time date in output files

Thank you Walaa, that's useful.

However I'm looking for something that I can access at runtime, like a property.

My final target is to create a procedure that verifies if the generated code is connected to a properly formatted database (or if the database structure is out of sync ).

By the way: isn't this a common problem? Is there a known "best practice" about it?

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 06-Jul-2018 09:42:45   

Ideally speaking, you should have your database deployment/upgrade scripts (whether state based or migration based) stored in a source control same as you do to your code (better in the same repository) so when you release and deploy, you do the same to the database as with your application. So you guarantee both are upgraded and in synch.

Yet you can still have some unit tests whether the logic is in code or in a stored procedure to check on that, possibly by comparing some version number stored in the database and in code (config file for example), this can also be triggered at runtime, maybe at the start of the application. Along with the rest of the Unit tests that should test your code against the database, and as you make changed to your code adding new functionality against some new schema modifications, these should have their Unit Tests in place.

So if you have your DevOps CI/CD set right with proper tests, you shouldn't have surprises about an outdated schema.

Valemus avatar
Valemus
User
Posts: 37
Joined: 09-Jan-2018
# Posted on: 06-Jul-2018 10:04:10   

Walaa wrote:

Ideally speaking, you should have your database deployment/upgrade scripts (whether state based or migration based) stored in a source control same as you do to your code (better in the same repository) so when you release and deploy, you do the same to the database as with your application. So you guarantee both are upgraded and in synch.

That's true for a single user environment, but when you have a shared database between more users it happens that if someone upgrades his own app and, at the same time, the common database all the other clients are out of synch.

Walaa wrote:

...by comparing some version number stored in the database and in code (config file for example)...

Yes, just wondering if there was any automatism about that, since upgrading manually the version that should be stored into the database and the value in the code is a procedure prone to errors and oversights.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 06-Jul-2018 18:18:56   

Hmm, it is a bit error prone regardless what you pick I think. I mean, a value in the DB somewhere needs to be updated if the schema is updated, but that's a manual operation (the RDBMS itself won't do that), reading that value in the designer and emitting it during code generation sounds plausible, but there's no check in place which verifies this: the value in the DB could have been updated again by someone else and you'll never know.

It's an interesting challenge, I don't know if there's a fail-proof solution for it though.

Frans Bouma | Lead developer LLBLGen Pro
Valemus avatar
Valemus
User
Posts: 37
Joined: 09-Jan-2018
# Posted on: 09-Jul-2018 09:10:43   

Otis wrote:

Hmm, it is a bit error prone regardless what you pick I think. I mean, a value in the DB somewhere needs to be updated if the schema is updated, but that's a manual operation (the RDBMS itself won't do that), reading that value in the designer and emitting it during code generation sounds plausible, but there's no check in place which verifies this: the value in the DB could have been updated again by someone else and you'll never know.

It's an interesting challenge, I don't know if there's a fail-proof solution for it though.

I propose a little idea: could it be possible to generate also a support class (like "DbInfo" or something like that) which exposes the datetime of the generated code?

It would greatly helps in cases like mine.

arschr
User
Posts: 893
Joined: 14-Dec-2003
# Posted on: 09-Jul-2018 16:13:07   

Wouldn't it need to be the date and time of the last database sync?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 09-Jul-2018 16:38:19   

@arschr that's a great point. As that date/time is indeed the one when both sides of the isle where in sync, so if you generate code 1 or 10 times after that, that doesn't make a difference.

@valemus: I like the idea, but as I said, it's a fragile affair regardless of what's done as there are several systems in play and there's nothing that enforces compatibility. So I lean to the idea of the last sync more than the last generation time...

thoughts?

Frans Bouma | Lead developer LLBLGen Pro
Valemus avatar
Valemus
User
Posts: 37
Joined: 09-Jan-2018
# Posted on: 09-Jul-2018 17:01:55   

Otis wrote:

@valemus: I like the idea, but as I said, it's a fragile affair regardless of what's done as there are several systems in play and there's nothing that enforces compatibility. So I lean to the idea of the last sync more than the last generation time...

Nothing to add, I agree simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 10-Jul-2018 10:55:58   

Please see: https://www.llblgen.com/Documentation/5.4/LLBLGen%20Pro%20RTF/Using%20the%20generated%20code/gencode_addingusercode.htm

to get started with adding a template to the generated code. See: https://www.llblgen.com/Documentation/5.4/SDK/TemplatesandTemplatebindings.htm for details regarding the template system and the syntax you can use (we recommend .lpt templates as you have full control over what you're accessing, TDL is limited and not extended anymore). I'd go for an include template so you can include the info somewhere. But you can also emit a separate class with static properties if you want. The designer ships with many .lpt templates, which you can peek into using the TemplateBindingsViewer to get more info about how things are done. It's just C# between <% %> like in asp.net.

The datetime values you're interested in are on the DBCatalog class, https://www.llblgen.com/Documentation/5.4/ReferenceManuals/Designer/html/482D45AB.htm namely the LastSyncWith* properties.

To obtain these values, you have to obtain the catalogs in scope. To do so, simply do (in your .lpt template):

HashSet<DBCatalog> existingCatalogs = _executingGenerator.GetCatalogsInScope();

And you can then loop over the DBCatalog and read the properties and emit the values into your code, like: (in your template, which emits code for a class)


// this is code that's emitted into the output, as it's not surrounded by <% %>
private Dictionary<string, DateTime?> _syncDatePerCatalog = new Dictionary<string, DateTime?>();

<%
// this is code that's template code and is run at generation time as it's surrounded by <%%>
foreach(var c in existingCatalogs)
{
%>  _syncDatePerCatalog.Add(c.CatalogName, c.LastSyncWithDatabaseUTC);
<%
}
%>

// and lower you're simply exposing it through a property, again code that's emitted into the output
public Dictionary<string, DateTime?> SyncDatePerCatalog
{
    get { return _syncDatePerCatalog; }
}

Good luck simple_smile

Frans Bouma | Lead developer LLBLGen Pro