Jump to content

Tom Chamberlain

Members
  • Content Count

    73
  • Joined

  • Last visited

Posts posted by Tom Chamberlain


  1. No dataaware, it is a kind of cheat/lazy way to do it :classic_biggrin:

    'Select * From TableWithBlod Where ID = -1', Open this to get an empty dataset (assuming you do not have a ID = -1), and that dataset 'knows' about the fields, when you do the append you can then get the stream to the blob field and fill it with raw data from the rich edit stream, set your ID and any other fields and call post then close.


  2. I use a TRichViewEdit which has other methods but this should work for a regular TRichEdit as well, do not treat it like a string stream, it's a blob stream.

     

    To save the RichEdit
     

    var
      BlobStream: TFDBlobStream;
    ...
    ... dbQuery = Select statement for the record that you want to update/create
    ...  
      dbQuery.Open;
      try
        ...
        ... dbQuery.Append; if you are creating a new record
        ...
        ... dbQuery.Edit; if you are editing one
        ...
        BlobStream := TFDBlobStream.Create(dbQuery.FieldByName('BlobFieldName') as TBlobField, bmWrite);
        try
          YourRichEdit.Lines.SaveToStream(BlobStream);
        finally
          BlobStream.Free;
        end;
        dbQuery.Post;
      except
        on e: exception do
          MessageDlg(e.Message, mtError, [mbOK], 0);
      end;
      dbQuery.Close;


    To load the RichEdit

     

    var
      BlobStream: TFDBlobStream;
    ...
    ... dbQuery = Select statement for the record that you want to read/load
    ...  
        dbQuery.Open;
        BlobStream := TFDBlobStream.Create(dbQuery.FieldByName('BlobFieldName') as TBlobField, bmRead);
        try
          if not dbQuery.FieldByName('BlobFieldName').IsNull then
            begin
              YourRichEdit.Lines.LoadFromStream(BlobStream)
            ...
            ... Not sure if there is anything RichEdit needs to update/format the display
            ...
            end;
        finally
          BlobStream.Free;
        end;
        dbQuery.Close;

     

    • Like 2

  3. 18 hours ago, RTollison said:

    generally speaking 10GB+ SQL server range from 2008r2 and up. Client last week had 42GB on SQL 2012 and it took about 40-45 minutes to complete the backup/restore process. This is run on the actual server while it is in use on the production database. and lots of times i see the SQL Server app using up 90% of the memory on those servers. sometimes i force clients to exit applications using the database then restart the SQL service, which drops the memory usage and then i run my app. < 20-30 minutes for a particular client who indicated that it had been running for 1.5 hrs.

     

    If your M$ SQL Server is NOT running at 80-90% memory it is not configured correctly, that's what it is suppose to do.  A maintenance plan is a must for any SQL Server database, rebuilding indexes for performance over time needs to be done for performance in general.   It takes our production system a little over a minute to backup a 6-7GB database during the day, the reason it only takes 20-30 minutes after you force the clients to exit is all the IO to the database stops, you could be fighting IO through-put and the SQL trying to get a good 'snap-shot' of the database.  Our production system is a small 16GB VMware VM running on a host with 14 other VM's all connected to a SAN running SSD's. (could I put more acronyms in there?)

     

    Is this a 24/7 system?

    They are making regular SQL backups right? You could just restore after that, if not there are bigger problems. (This could/should be a backup script job in SQL)

    Is this a physical server or a VM (Hyper-V/VMware/Proxmox)?

    They are not running some anti-virus that is looking at the database and/or backup folders are they? (anti-virus on the server is fine as long as the DB/backup folders are excluded, some cheaper A/V solutions are not smart enough to know not to to this)

    Does the database have lots of BLOB fields? If so are they on their own database partition(s)? (more of a performance issue if not)

     

    Never tried it but you may want to look into SQL Log Shipping instead of doing full backup/restore.  It should be able to be configured to run on the same server with different database names.


  4. 23 hours ago, Die Holländer said:

    RPG is a high-level programming language for business applications, introduced in 1959 for the IBM 1401.

    It was one of my first professional programming language before using Delphi and it was a delight to program in columns. 

     

    RPG has advanced beyond columns a long time ago with RPG Free.   I also started with RPG and COBOL on an IBM 4331, System/38 and AS/400 from the late 80's through early 2000's, good memories.  Even used Delphi/400 back when it first came out and I was learning Delphi.


  5. If your daily machine, PC or MAC has 16GB of RAM, is a multi-core CPU and has 100-150GB of free space go with a virtual machine.  There are free options like Hyper-V and VirtualBox even VMwares Workstation/Fusion is free for personal use.  Delphi will run in a VM with 4-6GB of RAM and a 2 cores, not speedy but it will run.   You can get a real copy of Windows 10/11 for cheap online and it's easy to backup with just a file copy.


  6. Use the TFDConnection object's GetInfoReport() method, it takes a string list.  It shows everything you want to know about the connection and the driver it used/picked.  We have this on our login/splash screen hidden behind a TLabel double-click event because we were having the same types of issues.  Also look into the FDDrivers.ini file configuration.

     

    ================================
    Connection definition parameters
    ================================
    DriverID=MSSQL
    Database=*******
    User_Name=*******
    Password=*****
    ODBCAdvanced=TrustServerCertificate=Yes;
    MARS=Yes
    Server=192.168.56.109
    VariantFormat=String
    ExtendedMetaData=True
    ================================
    FireDAC info
    ================================
    Tool = RAD Studio 12
    FireDAC = 29.0.51961.7529
    Platform = Windows 32 bit
    Defines = FireDAC_NOLOCALE_META;FireDAC_MONITOR
    ================================
    Client info
    ================================
    Loading driver MSSQL ...
      Loading odbc32.dll driver manager
      Creating ODBC environment handle
      Searching for ODBC driver ...
        Checking for ODBC driver [ODBC DRIVER 18 FOR SQL SERVER] ...
          Found [ODBC Driver 18 for SQL Server]
    Driver Manager version = 03.81.19041.0000
    ================================
    Session info
    ================================
    Checking session ...
      Warning: The client [18.3.3.0.0] and server [16.0.0.0.0] major versions difference > 1.
      Warning: MS ODBC 11 does not support SQL_VARIANT data type.
      Warning: SQL Server 2016 and compatibility level >= 130 may lead to DATETIME comparision failure.
    Current catalog = 
    Current schema = dbo
    Driver name = msodbcsql18.dll
    Driver version = 18.03.0003
    Driver conformance = 3
    DBMS name = Microsoft SQL Server
    DBMS version = 16.00.1130

     

    • Like 2

  7. Depends on the complexity of the data needed to create the record(s). The our app can have many child records for a parent, but requires at least one child, so we use a 'wizard' type screen for creating these initial records.  Our app is 25+yrs old, we have a mix of DB-aware for the the oldest forms, client datasets and even TMS string grids have been used to store data, but for 95% of all your 250+ tables we use one form for all create, view and edit of data.  If a table contains multiple records we use a grid of some type with a panel that we show/hide depending on the status of the selected record to create/edit the data.  We force the users to click an Edit button to change 99% of any data and then an Save or Cancel button.  


  8. We use a set of shared resource files,  one for the EXE's and another for the DLL's (the filetype changes) and leave the IDE out of it.  We have our own mass build process for production (the only time we care about the version numbers and things) with the option to update the version number, it changes and rebuilds the resource files before starting any compiles so we always have the correct versions for production.


  9. 12 hours ago, dormky said:

    Well, there's the client's own IT service (do not ask me why the IT service can't perform this simply backup, it's beyond me) that can access everything. Apparently we need to tell them what to install and how to use it.

    I'm honestly going to leave this request unanswered and hope people forget about it.

    Your joking right?  Is your database so large that it is not in a virtual server (hopefully on redundant hardware) with at least some sort of enterprise backup solution at a VM level?  Is the client so small or so cheap they do not understand this is not a software vendors job?  This sounds like a 'sales job' making you to come up with a solution for a non-problem or a completely incompetent IT service.  I am betting on the latter.

     

    Sarcasm:

     

    Tell them they need an SAS 18TB LTO tape drive attached to the server and something old-school like Restrospec or Backup Exec installed on the server for file-level backups and about 10-12 hours of down time each night to do the backups.  Don't forget to include someone has to swap that tape every day and they will need at least 100+ tapes for daily's, weekly's and monthly offsite storage.  Maybe you should offer to pickup the backups every morning and keep them safe offsite for them, for a extra fee of course.

     

    Sorry I slipped into a 1990's rant there, just glad I do not have to deal with this type of thing anymore.  Not making fun of anyone who still has to deal with tape backups I know their value to large organizations and disaster recovery plans.

     

     


  10. We have also been using ReportBuilder Enterprise for 15+ years since QuickReports was not capable of somethings we wanted to do so many years ago. 100's of reports later and that doesn't count the 'End User' reports the users have created themselves.  When COVID hit switching to emailing reports and invoice's saved so much time and paper, we have gone paperless and are not going back.  We have not had any performance issues (that were not self-inflicted) and when we have had technical issues, support is fast and responsive with patches.  I would also recommend ReportBuilder.


  11. 15 hours ago, Willicious said:

    It's the idea of instances-of-classes that keeps catching me out. If a class is defined somewhere, it should be callable as that class. Why do I have to redefine/redeclare it in a different unit? Why not this instead:

    Unit 1
        Class1

              PropertyA

     

    Unit 2

        uses

             Class1

     

    if Class1.PropertyA etc...
     

     

    The one thing no one has pointed out:

     

    Unit1

      TClass1

         PropertyA

     

    Unit2

      Uses

        Unit1 {the unit name, not the class inside the unit name}

     

    Another useful link is https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Programs_and_Units_(Delphi)

     

    • Like 1

  12. If you own D11.3 Enterprise or Architect and all your apps are Delphi then you can create your own solution with DataSnap.  You can use the TDSClientCallbackChannelManager to register client applications with a DataSnap server.  Your client applications make function/procedure calls to the DataSnap server using regular types and classes to do what you want, DataSnap will do all the marshalling for you both ways.  We use such processes to track concurrent usage with a 'user' object we pass that contains user name, machine name, IP, database they are connected to, etc.  We have created our own 'message' structure that allows us to send notifications to individual clients or all registered clients via the callback or issue 'commands' to the clients to close the application gracefully if the user forget to logout at the end of the day.  The callback from the server sends a TJSONValue so you can build a simple or very complex message architecture.  (Interacting with the client GUI requires some TThead.Queue calls but this will be true of any solution)

     

    If your apps use multiple languages then something like ActiveMQ, ZeroMQ, RabbitMQ, etc. would be a better solution, but if your apps are all Delphi you may already have the tools/tech you need.  That said, if you have more than 5,000 active clients I would not use DataSnap, but look for something that scales better than DataSnap.  We are small and only have 20-30 active clients at most so DataSnap is a simple and flexible solution for us.

     

     


  13. 4 hours ago, Lars Fosdal said:

    CoInit/CoUnInit -  Prior to starting DB components, and after the last disconnect

    I do this because I have zero control over what a DB driver does with regards to COM.

    Interesting, we only call CoInit/CoUnInit in new threads before/after new connections are created/freed, never in the main (GUI) thread which has DB queries and data-aware components (to many, but 20+yr old code) but only one shared DB connection for the GUI in a data module.  But every thread inside services get CoInit/CoUnInit's.  We have only ever used M$/SQL, used the BDE for the first 5yrs and switched to ADO in 2003 or 2004 which has be sufficient for our needs until changes to M$/SQL date field types have forced us to make the switch to FireDac and the latest ODBC SQL drivers.  We have had some learning pain's with FireDac but nothing like theses issues. 

     

     


  14. In our 24+ year old system we have a central TDataModule with the connection and shared data access for things used everywhere like customer information retrieval.  Then each form has form specific queries/datasets/command and datasource components dropped on them (no tables) for the form related data.  We don't have a sea of DB components on most forms, but if I could go back 25 years knowing what I know now, I would do it all through objects and/or use some type of ORM and have no DB components anywhere.  Now, where is my Tardis?


  15. Do not waste your time, find a new job and leave them in the past.

    Got reprimanded once for replacing 2000+ lines of code looking for values by doing 'if Edit1.Value = x' on about 200 edit boxes basically named Edit1, Edit2, Edit3..Edit200 on a form (don't ask), just a huge cut-paste, change the component name procedure. I reduced it to about 10 lines using FindComponent in a loop producing the same results.  I walked out of that job in less than 1 month after I figured out they (staff and management) refused to learn anything new. :classic_cool:

     

    Do not suffer fools.

    • Like 3

  16. It works better if you can break it down and use a key for the child objects also:

     

    TChildList = TObjectDictionary<UniqueKey, TMyClass>;

    MyList: TObjectDictionary<String, TChildList>;

     

    UniqueKey is a priority/sequence number in our system for each unique child, we use an integer.  This makes searching and processing child objects simple.

    var
     localChild: TMyclass;
    
    if MyList.ContainsKey(SearchString) then
     for localChild in Mylist[SearchString].Values do
      begin
    
        localChild.....whatever
    
      end;

    and

    if MyList.ContainsKey(SearchString) then
     if MyList[SearchString].ContainsKey(UniqueKey) then
      begin
       localChild := MyList[SearchString].Items[UniqueKey];
       
       localChild...whatever
      
      end;

     

    • Thanks 1
×