[Gelöst] - Probleme beim Löschen von alten Objekten

14. Mai 2015 17:14

Hallo zusammen

Ich bin an einer Datenbankmigration 2009R2 -> 2013R2. In dieser Datenbank sind Objekte drin die irgendwann einmal eingelesen aber nie verwendet wurden (Tests o.ä).
Da hier aber Forms und Dataports drin sind gibt das nun Probleme, da die ja raus müssen weil 2013 die nicht mehr kennt.

Leider sind die Objekte in einem Nummernbereich ausserhalb der Lizenz, inkl. meiner aktuellen Partnerlizenz. Somit kann ich diese Objekte nicht löschen.

Ich weiss, dieses Problem wurde schon verschiedentlich diskutiert. Aber die angebotenen Lösungen waren mir entweder zu gefährlich (SQL-Scripts auf dbo.objects) oder sie funktionieren nicht (mehr) wie die 'Killer-Objekte' da ich ja ein leeres Objekt mit der Nummer des zu Löschenden anlegen müsste was aber eben nicht geht wegen der fehlenden Rechte in der Lizenz.

Deshalb wage ich es hier, nochmals eine Diskussion darüber zu eröffnen in der Hoffnung, das es mittlerweile vielleicht andere Lösungen dazu gibt.

Besten Dank schon mal für jeden Tipp,
Zuletzt geändert von rotsch am 16. Mai 2015 10:24, insgesamt 1-mal geändert.

Re: Probleme beim Löschen von alten Objekten

14. Mai 2015 21:00

Die notwendigen Killerobjekte sollte man beim Lieferant dieser Objekte anfordern können (oder dessen Rechtsnachfolger).
viewtopic.php?f=66&t=25717&p=107206&#p107206

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 09:08

Kowa hat geschrieben:Die notwendigen Killerobjekte sollte man beim Lieferant dieser Objekte anfordern können...


Danke Kai, daran hatte ich auch schon gedacht. Hab mal geschrieben, mal sehen, ob was kommt. Da scheint schon länger nichts mehr zu gehen mit diesem Tool. Es nennt sich DBPORT, ev. kennt das jemand, oder hat einen Tipp hierzu?

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 13:11

Eine Alternativlösung wäre auch, alle lizenzierten Objekte in eine frisch aufgesetzte NAV 2009 R2 Basisdatenbank zu importieren und danach per FBK nur die Mandantendaten aus dem Echtsystem einzuspielen und von dort die weitere Konvertierung vorzunehmen. Das kann natürlich etwas dauern, je nach Datenbankgröße.

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 13:36

Ich mache mir für solche Fälle eine Excel-Tabelle in der in Spalte A die Tabellennummern stehen. In Spalte B dann die folgende Formel (hier für A1, sinngemäß dann für alle anderen Zeilen):
Code:
=CONCATENATE("INSERT INTO [Object] (Type,ID,Name,[Company Name],[Locked By],Modified,Compiled,[BLOB Size],[DBM Table No_],[Date],[Time],[Version List],Locked) VALUES (1,";A1;",'KILL Table ";A1;"','','',0,0,0,0,'1753-01-01 00:00:00.000','1753-01-01 00:00:00.000','',0);")

Damit kann man in einer leeren bzw. CRONUS-Datenbank leere (Kill-)Objekte anlagen, diese exportieren und dann in die Zieldatenbank importieren. So werden dort die Objekte gelöscht, auch wenn man selbst keine Objekte in den Nummerbereich erstellen kann. Vorteil: Man muss nicht direkt in der Zieldatenbank die Objekttabelle von "außen" beschreiben.

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 15:12

SilverX hat geschrieben:Ich mache mir für solche Fälle eine Excel-Tabelle...


Hallo Carsten,
Danke für den Tipp, das klingt eigentlich gut. Ich nehme an, das geht auch für andere Objekte wie Dataports, Forms, usw., oder?

Was mir nicht klar ist: Was mache ich mit der Excel-Tabelle genau, damit ich Kill-Objekte erhalte?

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 15:13

Kowa hat geschrieben:Eine Alternativlösung wäre auch, alle lizenzierten Objekte in eine frisch aufgesetzte NAV 2009 R2 Basisdatenbank zu importieren...


Das funktioniert mit allen Objekten, ausser mit Tabellen, die kommen mit einem FBK ja auch mit.

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 15:18

Was mir nicht klar ist: Was mache ich mit der Excel-Tabelle genau, damit ich Kill-Objekte erhalte?


Nun das ganze wird eigentlich auch ein SQL-Skript. Dieses Skript führst du wahrscheinlich auf einer Cronus oder sogar leeren DB aus. Du bekommst dadurch deine "Killer"- Objekte, die du exportieren und in deine Kunden-DB importieren kannst.

Gruß Fiddi

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 16:09

fiddi hat geschrieben:
Was mir nicht klar ist: Was mache ich mit der Excel-Tabelle genau, damit ich Kill-Objekte erhalte?


Nun das ganze wird eigentlich auch ein SQL-Skript. Dieses Skript führst du wahrscheinlich auf einer Cronus oder sogar leeren DB aus. Du bekommst dadurch deine "Killer"- Objekte, die du exportieren und in deine Kunden-DB importieren kannst.

Gruß Fiddi
Korrekt. Per Excel wird das ein SQL Script, natürlich können auch andere Objekttypen enthalten sein (Table=1; Form=2; Report=3; Dataport=4; Codeunit=5; XMLport=6; MenuSuite=7; Page=8; Query=9).

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 19:02

rotsch hat geschrieben:Das funktioniert mit allen Objekten, ausser mit Tabellen, die kommen mit einem FBK ja auch mit.

Sicher, in deinem ersten Beitrag ging es aber um Forms und Dataports, die gelöscht werden sollen.

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 19:17

Kowa hat geschrieben:Sicher, in deinem ersten Beitrag ging es aber um Forms und Dataports, die gelöscht werden sollen.


Stimmt, das habe ich geschrieben. Da war ich zu ungenau, tut mir leid. Es sind auch Tabellen dabei.

Re: Probleme beim Löschen von alten Objekten

15. Mai 2015 23:06

fiddi hat geschrieben:Nun das ganze wird eigentlich auch ein SQL-Skript. Dieses Skript führst du wahrscheinlich auf einer Cronus oder sogar leeren DB aus. Du bekommst dadurch deine "Killer"- Objekte, die du exportieren und in deine Kunden-DB importieren kannst.

SilverX hat geschrieben:Korrekt. Per Excel wird das ein SQL Script, natürlich können auch andere Objekttypen enthalten sein (Table=1; Form=2; Report=3; Dataport=4; Codeunit=5; XMLport=6; MenuSuite=7; Page=8; Query=9).

Würde es jemandem etwas ausmachen, das ein wenig detaillierter zu erklären? Ich verstehe nur Bahnhof. :roll:

Re: Probleme beim Löschen von alten Objekten

16. Mai 2015 10:24

Also, ich hab's nun geschafft, die lästigen Objekte loszuwerden. Herzlichen Dank an alle für alle Tipps, Antworten und Hilfestellungen. Ich habe es mit der Methode von SilverX/Carsten gemacht.

Folgendes dazu:
Die Geschichte mit dem Excel habe ich nicht hinbekommen. Ich hab zwar die beiden Spalten wie beschrieben aufgebaut, jedoch hatte ich dann in Spalte B immer noch die Bezeichnungen A1, A2 usw. drin anstelle der ObjektID. Aber das hat mir schlussendlich doch weitergeholfen.

Ich habe eine neue, leere DB erstellt. Dann habe ich mit dem SQL Management-Studio die Datenbank geöffnet und einen Script erstellt nach der Vorlage von Carsten. Der sieht so aus (am Besipiel einer zu löschenden Codeunit)

Code:
INSERT INTO [Object]
   ([Type],
   [ID],
   [Name],
   [Company Name],
   [Locked By],
   [Modified],
   [Compiled],
   [BLOB Size],
   [DBM Table No_],
   [Date],
   [Time],
   [Version List],
   [Locked])
 VALUES
  (5,
  6109813,
  'KILL Codeunit13',
  '',
  '',
  0,
  0,
  0,
  0,
  '1753-01-01 00:00:00.000',
  '1753-01-01 00:00:00.000',
  '',
  0);


Dann habe ich einfach pro zu löschendes Objekt den Script angepasst und immer wieder laufen lassen. Am Schluss hatte ich in meiner leeren DB alle nötigen KillerObjects drin (siehe Screenshot), und konnte die Objekte dann in der produktiven DB für den Löschvorgang einsetzen.

Wichtig in diesem Zusammenhang: Im Codebeispiel von Carsten stimmt die Syntax nicht überall, das müsst ihr anpassen. Jede Spaltenbezeichnung muss in [ ] eingefasst werden. Das hat zum Teil gefehlt und führte zu Fehlern, ist aber schnell behoben.

Also, nochmals herzlichen Dank, das hat mit alles sehr geholfen :-D :-D
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: Probleme beim Löschen von alten Objekten

16. Mai 2015 10:34

Hintergrund ist per SQL in einer (idealerweise leeren) Datenbank in der Object-Tabelle leere Objekte zu erzeugen. In der Entwicklungsumgebung funktioniert das nicht, deshalb der Umweg über den SQL Server bzw. das SQL Server Management Studio.

Mein Ansatz war, eine Excel Tabelle zu nutzen in der die Objektnummern in Spalte A stehen und eine Formel in Spalte B, die die SQL-Query enthält und ein leeres Objekt erzeugt. Diese können dann über die Entwicklungsumgebung exportiert werden und dienen in anderen Datenbanken als Kill-Objekte.

Besser geht es natürlich mit der PowerShell 8-)

Ein (sehr wahrscheinlich nicht ganz ausgereiftes) Beispiel:

Code:
Import-Module 'C:\Program Files\Microsoft Dynamics NAV\80\Service\Microsoft.Dynamics.Nav.Management.psm1';
Import-Module 'C:\Program Files (x86)\Microsoft Dynamics NAV\80\RoleTailored Client\Microsoft.Dynamics.Nav.Ide.psm1';


$ObjectType = [PSCustomObject] @{ Table=1; Form=2; Report=3; Dataport=4; Codeunit=5; XMLport=6; MenuSuite=7; Page=8; Query=9 }

Add-Type -TypeDefinition @"
    public enum ObjectType
    {
        Table=1,
        Form=2,
        Report=3,
        Dataport=4,
        Codeunit=5,
        XMLport=6,
        MenuSuite=7,
        Page=8,
        Query=9
    }
"@


function Remove-Database()
{
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]$DatabaseServer,
   
        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateNotNullOrEmpty()]
        [string]$DatabaseName
    )

    PROCESS
    {
        Import-Module 'sqlps' -DisableNameChecking
        Push-Location;

        $smoServer = New-Object Microsoft.SqlServer.Management.Smo.Server $DatabaseServer;
       
        if ($smoServer.Databases.Contains($DatabaseName))
        {
            Write-Verbose "Removing database $DatabaseServer/$DatabaseName.";

            $smoServer.KillAllProcesses($DatabaseName);
            $smoServer.Databases[$DatabaseName].Drop();
        }

        Pop-Location;
    }
}


function New-NavObjectArrayFromFilter()
{
    Param(
        [Parameter(Mandatory = $true, Position = 0)]
      [string]$Filter
    )

    Process
    {
        $filterArray = $filter.Split('|');
        $objectIdArray = @();

        ForEach($f in $filterArray)
        {
            if ($f.Contains('..'))
            {
                $f2 = $f.Split(@('..'), [System.StringSplitOptions]::RemoveEmptyEntries);
                $from = [int]$f2[0];
                $to = [int]$f2[1];

                For ($i = $from; $i -le $to; $i++)
                {
                    $objectIdArray += $i;
                }
            }
            else
            {
                $objectIdArray += [int]$f;
            }
        }

        return $objectIdArray;
    }
}


function New-NavApplicationKillObject()
{
    [CmdletBinding()]
   Param(
        [Parameter(Mandatory = $true, Position = 0)]
      [string]$DatabaseServer,

        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateSet('Table', 'Form', 'Report', 'Dataport', 'Codeunit', 'XMLport', 'MenuSuite', 'Page', 'Query')]
      [string]$Type,

        [Parameter(Mandatory = $true, Position = 2)]
      [string]$IdFilter,

        [Parameter(Mandatory = $true, Position = 3)]
      [string]$Path
    )

    Process
    {
        $databaseName = ('NavKillObjects_{0}' -f [System.Guid]::NewGuid().ToString().Replace('-', ''));
        $killObjectType = ([ObjectType] $Type) -as [int];
        $objectIdArray = New-NavObjectArrayFromFilter -Filter $IdFilter;

        Import-Module 'sqlps' -DisableNameChecking
        Push-Location;

        Create-NAVDatabase `
            -DatabaseServer $DatabaseServer `
            -DatabaseName $databaseName;

        $query = '';

      ForEach($objectId in $objectIdArray)
        {
            $query += "INSERT INTO [Object] ([Type],[ID],[Name],[Company Name],[Locked By],[Modified],[Compiled],[BLOB Size],[DBM Table No_],[Date],[Time],[Version List],[Locked]) VALUES ($killObjectType,$objectId,'Kill $Type $objectId','','',0,0,0,0,'1753-01-01 00:00:00.000','1753-01-01 00:00:00.000','',0);`r`n";
        }

        Invoke-Sqlcmd `
            -ServerInstance $DatabaseServer `
            -Database $databaseName `
            -Query $query;

        Export-NAVApplicationObject `
            -DatabaseServer $DatabaseServer `
            -DatabaseName $databaseName `
            -Path $Path `
         -Filter 'ID=1..2000000000' `
            -Force;

        Remove-Database `
            -DatabaseServer $databaseServer `
            -DatabaseName $databaseName;

      Pop-Location;
    }
}


Aufruf über:
Code:
New-NavApplicationKillObject -DatabaseServer '<Sql Server>' -Type Table -IdFilter '5157800..5158000' -Path 'C:\Temp\TableKillObjects.fob';
Ein entsprechender sinnvoller Filter natürlich vorausgesetzt.

Da die Filter per Code ausgewertet werden, können hier nur '|' und '..' verwendet werden. Der Range Operator auch nur komplett, also nicht ..X oder Y..

Re: [Gelöst] - Probleme beim Löschen von alten Objekten

16. Mai 2015 12:56

Ich habe den tollen Ansatz von Carsten auch mal weiterverfolgt und mein SQL-Skript so gestaltet, dass man dort die benötigten Bereiche direkt eintragen kann.
Im Beispiel geht es von Tabelle 123456 bis 123465.
Code:
DECLARE @MyObjectID int;
DECLARE @MyObjectDateTime datetime;
DECLARE @MyObjectName nchar(30);

SET @MyObjectID = 123456;
SET @MyObjectDateTime = '1753-01-01 00:00:00.000';

WHILE (@MyObjectID < 123466)
BEGIN;
  SET @MyObjectName = CONCAT('KILL Table :',@MyObjectID)
  INSERT INTO dbo.Object
  (Type,
  ID,
  Name,
  [Company Name],
  [Locked By],
  Modified,
  Compiled,
  [BLOB Size],
  [DBM Table No_],
  [Date],
  [Time],
  [Version List]
  ,Locked)
  VALUES (1,@MyObjectID,@MyObjectName,'','',0,0,0,0,@MyObjectDateTime,@MyObjectDateTime,'',0)
  SET @MyObjectID = @MyObjectID + 1;
END;

Ergebnis dieses Skripts in der KILLEROBJECTS-Datenbank:
KillTable.jpg

Das Objektpaket im Import Worksheet der Zieldatenbank, "angetreten zur Entrümpelung " :-) .
KillTable2.jpg
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.