Fortuna Entwickler Blog

Hier wird Ihnen geholfen

Xcode mit TFS verbinden

Es gibt nun ein Git-Repository auf unserem TFS:

http://tfs.gutingia.local:8080/tfs/DefaultCollection/_git/Xcode

Zuerst einmal: Die Arbeit mit einem Git-Repository ist grundlegend anders als wir das bisher mit TFS gewohnt sind. Hiermit werde ich mich noch gesondert beschäftigen.

Um nun ein Projekt in diesem Repository abzulegen, holt man sich idealerweise erst einmal das bestehende Repository. Das Ganze geht am besten über die Kommandozeile. Im Launchpad unter Andere findet man das Terminal. Hier wechselt man in das Verzeichnis, in welchem das Repository abgelegt werden soll und gibt dann ein Git-Kommando ein:

git clone http://tfs.gutingia.local:8080/tfs/DefaultCollection/_git/Xcode

Damit holt man sich den aktuellen Inhalt aus dem Repository.

Anschliessend kann man Xcode starten und wenn man ein neues Projekt anlegt, wählt man den Ordner "Xcode" aus, welcher durch den Git-Befehl oben erstellt wurde. Fertig.

Mac einrichten und ins Firmennetzwerk einbinden

Um einen Mac in ein Windowsnetzwerk einzubinden muss man einige, wenige Einstellungen vornehmen. Bei der Erstinstallation muss man auf jeden Fall einen lokalen Benutzer anlegen, der dann auch lokaler Admin ist. Mit diesem Account kann man dann lokal alles einstellen; ich habe den lokalen Benutzer myLife genannt; das Passwort dazu ist der Administration (Sascha/Erico) bekannt.

Zentraler Anlaufpunkt für alle Änderungen sind die Systemeinstellungen, die man unten im Dock findet:

Zuerst einmal sollte man sicherstellen, daß man sich im Firmennetzwerk befindet. Also entweder ist der Mac per Netzwerkkabel angeschlossen, oder im mylifeLAN angemeldet. Das Passwort für dieses WLAN ist der Administration bekannt.

Im ersten Schritt gibt man dem Mac einen im Netzwerk eindeutigen Namen. Dies sollte in Absprache mit Sascha/Erico geschehen. Den Anfang gemacht haben die Namen MacBook01 und MacMini01. Den Namen vergibt man in den Systemeinstellungen unter Freigaben.
Laut einigen Seiten im Internet kann es sein, daß man sich nach einem Wechsel des Namens einmalig Ab- und wieder Anmelden oder besser noch, den Mac neu starten sollte.

Als nächstes sollte man den Proxy eintragen, damit man schon einmal Verbindung 'nach draußen' hat. Dies geschieht in den Systemeinstellungen unter Netzwerk. Dort unter Weitere Optionen und dann unter Proxies.

Die eigentliche Anmeldung im Netzwerk geschieht dann unter Benutzer & Gruppen in den Systemeinstellungen. Hier muss man das Bearbeiten der Einstellungen erst einmal über das Schloss unten (und Eingabe des Passworts) freigeben.
Dann klickt man auf Anmeldeoptionen und dort dann auch Netzwerk-Account-Server Verbinden...
Dort gibt man dann den Namen des Domain Controllers/AD-Servers an und wird dann nach Benutzername und Kennwort gefragt. Hier ist ein Benutzer anzugeben, welcher Administrationsrechte im Netzwerk hat. Nach klick auf OK sollte sich der Mac im Netzwerk einbinden.
Es kann unter umständen Probleme geben bzw. die Anmeldung funktioniert nicht, wenn es zwischen dem AD-Server und dem Mac einen Zeitunterschied von 5 Minuten oder mehr gibt. Dies liegt laut einer Webseite in der Verschlüsselung der Übertragung begründet. Wenn also etwas nicht klappt, sollte man das als Erstes mal prüfen.

Zurück in den Anmeldeoptionen sollte man oben noch die Option Name und Kennwort wählen; Liste der Benutzer ist in einem Netzwerk nicht sinnvoll.

Ich habe zudem die Option Menü für schnellen Benutzerwechsel abgewählt.

Das war es dann auch schon. Gegebenenfalls nach einem Neustart kann man sich mit Benutzername/Kennwort aus dem Netzwerk an selbigem anmelden.

RESTful Service erstellen und Konsumieren mit RestSharp

Ich habe mich im Rahmen der Restschuldversicherung für die von Essen Bank mal mit RESTful Services beschäftigt, da ich eine ganze Reihe an Daten an den Service übergeben muss und auch viele Daten zurückbekomme, liegt der Fokus erst einmal auf POST.

Das Ganze wollte ich erst einmal einfach halten, um bei etwaigen Fehlern nicht in Unmengen von Code zu suchen. Also habe ich erst einmal mit einem ganz kleinen Service begonnen.

In Visual Studio habe ich ein neues Projekt erstellt: Installed -> Visual C# -> WCF -> WCF Service Application. Im neuen Projekt bekommt man dann ein Interface und einen Service vorgegeben, die man nach eigenem Gusto benennen kann. In meinem Fall war dies hinsichtlich des eigentlichen Ziels Fortuna.RSV.Services

Im Interface (Fortuna.RSV.Services.IRSVCalc.cs) habe ich dann erst mal einen ganz einfachen Service angelegt:

        [OperationContract]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "Berechnen")]
        int Berechnen(int i);

Der zugehörige Code (Fortuna.RSV.Services.RSVCalc.svc.cs) im Service selbst ist dazu denkbar einfach:

        public int Berechnen(int i)
        {
            return i * 2;
        }

In der Web.config ist der Service zudem noch einzutragen:

  <system.serviceModel>
    <services>
      <service name="Fortuna.RSV.Services.RSVCalc" behaviorConfiguration="serviceBehavior">
        <endpoint address="" binding="webHttpBinding" contract="Fortuna.RSV.Services.IRSVCalc" behaviorConfiguration="web"></endpoint>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="serviceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>

Damit ist der Service auch schon fertig und grundsätzlich einsatzbereit. Man kann ihn schon im Visual Studio testen.

Nun wollte ich natürlich auch mal sehen, wie man den Service konsumieren kann. Natürlich geht das, indem man einen Request an den Service schickt und die Response auswertet. Anstatt alles 'von Hand' zu machen, habe ich mich entschieden, RestSharp zu verwenden. Informationen dazu findet man auf RestSharp.org und man kann das Package über nuget in sein Projekt einbinden.

Um das nun zu testen habe ich ein neues Projekt (einfach eine C# ClassLibrary) hinzugefügt und über nuget RestSharp in den Referenzen ergänzt. Das Projekt habe ich Fortuna.RSV.ServiceClient genannt, aus class1.cs wurde RSVService.cs:

    public class RSVService
    {
        private string _ServiceBaseUri;
        public RSVService()
        {
        }
        public RSVService(string Uri)
        {
            _ServiceBaseUri = Uri + "RSVCalc.svc/";
        }
        public int Berechnen(int Eingabe)
        {
            int Ausgabe = 0;
            var client = new RestClient(_ServiceBaseUri);
            var request = new RestRequest("Berechnen", Method.POST);
            request.RequestFormat = DataFormat.Json;
            request.AddBody(Eingabe);
            var response = client.Execute(request);
            if (response.ResponseStatus == ResponseStatus.Completed)
                Ausgabe = int.Parse(response.Content);
            return Ausgabe;
        }
    }

Was passiert hier in der Methode Berechnen?

Es wird ein RestClient erstellt; dies ist ein Objekt, welches von RestSharp zur Verfügung gestellt wird. Als Parameter wird die Uri des Service angegeben. Selbige wird im Konstruktor meiner Klasse übergeben. Anschliessend wird der RestRequest definiert. Auch dies ist ein Objekt von RestSharp. Hier geben wir schon an, wie die Methode heisst, die aufgerufen wird, in unserem Fall 'Berechnen', was dem Wert entspricht, der oben als 'UriTemplate' im Contract steht. Als Methode habe ich auch hier (wie im Contract) POST definiert. Ebenso analog zum Contract verwende ich JSON als Datenformat.

Der Parameter (int i) wird dem RequestBody hinzugefügt; RestSharp kümmert sich um die Serialisierung in JSON, was in diesem Fall denkbar wenig ist, aber für die eigentliche Zielsetzung durchaus von Belang ist.

Anschliessend wird der Request mit Execute ausgeführt und das Ergebnis (die Response) in einer Variablen abgelegt. Das Ergebnis des Service erhält man bei dieser Art des Aufrufs in der RestResponse-Property 'Content'. Fertig.

Hier würde natürlich erst mal alles ganz einfach gehalten: Ein integer wird übergeben und ein integer wird zurückgeliefert. Im nächsten Schritt wollte ich dann ein einfaches Objekt mit zwei integer-Werten liefern und einen integer zurückbekommen. Im Service-Interface sieht das dann so aus:

        [OperationContract]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "Berechnen3")]
        int Berechnen3(BerechnenClass data);

Die Berechnen Class ist denkbar übersichtlich:

    [DataContract(Namespace="http://fortuna.mylife-leben.de/RSV")]
    public class BerechnenClass
    {
        [DataMember]
        public int parm1 { get; set; }
        [DataMember]
        public int parm2 { get; set; }
    }

Und auch den Code des Service habe ich einfach gehalten:

        public int Berechnen3(BerechnenClass data)
        {
            return data.parm1 * data.parm2;
        }

In der Web.config ist jetzt nichts weiter einzutragen; der Service ist dort ja bereits vorhanden; es kommt nur eine neue Methode dazu.

Im Client benötige ich natürlich auch das Objekt und der Code ist in grossen Teilen mit dem ersten identisch:

        public int Berechnen3(int parm1, int parm2)
        {
            BerechnenClass c = new BerechnenClass() { parm1 = parm1, parm2 = parm2 };
            int Ausgabe = 0;
            var client = new RestClient(_ServiceBaseUri);
            var request = new RestRequest("Berechnen3", Method.POST);
            request.RequestFormat = DataFormat.Json;
            request.AddBody(c);
            var response = client.Execute(request);
            if (response.ResponseStatus == ResponseStatus.Completed)
                Ausgabe = int.Parse(response.Content);
            return Ausgabe;
        }

Auch hier wieder: Client erstellen, Request erstellen, dann aber eben das zu übergebende Objekt dem RequestBody hinzufügen, die Serialisierung nach JSON wird von RestSharp übernommen, dann der Aufruf des Services und die Verarbeitung der Response. Fertig.

Nachdem auch dies funktioniert wollte ich nun das Objekt übergeben, welches zur Berechnung und als Ergebnis bei der Restschuldversicherung bereits vorhanden ist. Ein Klasse mit deutlich über 30 Parametern, sowohl integer als auch double Werte, also schon etwas größer als das, was ich hier bisher verwendet habe. Die Klasse heisst 'RSVdaten'

Das Interface ist ähnlich wie gehabt:

        [OperationContract]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "Berechnen2")]
        RSVdaten Berechnen2(RSVdaten data);

Der Code im Service ist sehr einfach, weil die eigentliche Berechnung in C++ abgebildet ist:

        public RSVdaten Berechnen2(RSVdaten data)
        {
            RSVInterfaceUnmanaged.ClassRSVBer myClass = new ClassRSVBer();
            myClass.ber(data);
            return data;
        }

Während dies alles nicht weiter aufregend ist, gab es jetzt für den Client eine gewisse Herausforderung. Bisher haben die Methoden int zurückgeliefert, hier jetzt aber ein komplexes Objekt. RestSharp bietet hier eine schöne Variante des 'Execute' an:

        public RSVdaten Berechnen2(RSVdaten data)
        {
            RSVdaten Ausgabe = new RSVdaten();

            var client = new RestClient(_ServiceBaseUri);
            var request = new RestRequest("Berechnen2", Method.POST);
            request.RequestFormat = DataFormat.Json;
            request.AddBody(data);

            var response = client.Execute<RSVdaten>(request);
            if (response.ResponseStatus == ResponseStatus.Completed)
                Ausgabe = response.Data;

            return Ausgabe;
        }

Beim Execute gibt man bereits an, von welchem Typ man die Response erwartet. Den Inhalt findet man dann nciht im Parameter Content, sondern in Data, welcher dann schon vom angegeben Typ ist. Mehr ist auch hier nicht zu tun.

Auswertungen Tschechien

Jeden Monat benötigt Finanzen eine Reihe von Auswertungen. Diese gehen als Excel-Tabellen an Almut bzw. deren Vertretung.

BCAS schick üblicherweise zwischen dem 21. und 23. jeden Monats die Daten an den Service. Die Daten sind dann auf WEBDATA abgelegt. Alle relevanten Tabellen beginnen mit 'BCAS'.

Bevor die Auswertungen erstellt werden, muss der Status bei jedem Vertrag geprüft und ggf. aktualisiert werden. Dies passiert durch den Aufruf einer Stored Procedure:

EXEC BCAS_IO.BCAS_STATECHANGE();

Anschliessend können die Reports abgerufen werden. Das Ergebnis wird jeweils in einer Excel-Datei gespeichert; der Dateiname steht im Kommentar über dem jeweiligen Statement (MM_YYYY austauschen gegen Monat / Jahr)

-- Exportdatei: BCAS_POLICYOVERVIEW_MM_YYYY
SELECT * FROM BCAS_POLICYOVERVIEW ORDER BY UEBERMITTELT_AM, POLICYNUMBER;

-- Exportdatei: BCAS_PAYMENTOVERVIEW_MM_YYYY
SELECT * FROM BCAS_PAYMENTOVERVIEW ORDER BY UEBERMITTELT_AM, POLICYNUMBER;

-- Exportdatei: BCAS_PAYMENTOVERVIEW_BY_MONTH_MM_YYYY
SELECT * FROM BCAS_PAYMENTOVERVIEW_BY_MONTH;

-- Exportdatei: BCAS_POLICYOVERVIEW_MONTHLY_MM_YYYY
SELECT * FROM BCAS_POLICYOVERVIEW_MONTHLY bpm;

-- Exportdatei: Monatsübersicht_YYYY_MM

--Monatsübersicht: + Commission SK
SELECT
			TO_CHAR(bp.UEBERMITTELT_AM, 'YYYY-MM') AS Monat,
			SUM(bp."value") AS  "Gebuchte Beiträge",
      0 AS "Rücklaufleistung",
      0 AS "Todesfallleistung",
      SUM(ROUND(bp.IC_BCAS / 12, 0)) AS "Provision BCAS",
      SUM(ROUND(bp.IC_SK / 12, 0)) AS "Provision SK",
      SUM(ROUND((bp.IC_SK) / 12, 0)) +ROUND(SUM(bp."Diff"), 0) AS "Provision SK2",
--	ROUND(SUM(bp."Diff"), 0) AS "Diff",
			ROUND(SUM(bp.RE / 12), 0) AS "RV-Beiträge",
      0 AS "RV-Leistungen",
      ROUND(SUM(bp.RE) / 12 * 2.5 / 100, 0) AS "RV-Provisionen",
			ROUND(SUM(ROUND(bp.C, 0) / 12), 0) AS "Costs of Insurance"
	FROM BCAS_PAYMENTOVERVIEW bp
  GROUP BY TO_CHAR(bp.UEBERMITTELT_AM, 'YYYY-MM')--, BP1.STATE
  ORDER BY TO_CHAR(bp.UEBERMITTELT_AM, 'YYYY-MM')--, BP1.STATE
	;


Als weiteren Report gibt es eine Statusübersicht. Diese wird monatlich fortgeschrieben. Man führt also das nachfolgende SQL-Statement aus, kopiert den Report des Vormonats und fügt die Daten des neuen Monats hinzu:

-- Juli 2014
WITH SEL_WERTE AS (SELECT TO_DATE('31.07.2014', 'DD.MM.YYYY') AS SEL_DATE FROM DUAL)
SELECT  BS.ID AS STATEID, BS."name" AS STATE, COUNT(SEL.ID) AS ANZAHL, NVL(SUM(SEL2.PAYMENT), 0) AS PAYMENT, NVL(SUM(SEL.SUMASSURED), 0) AS SUMASSURED
  FROM  BCAS_STATE BS
  LEFT OUTER JOIN
  (
    SELECT BP.ID, BCAS_IO.BCAS_IP_STATE_BY_DATE(BI.ID, (SELECT SEL_DATE FROM SEL_WERTE)) AS STATEID, BI.SUMASSURED
      FROM  BCAS_TRANSFER BT
      INNER JOIN BCAS_POLICY BP ON BT.ID = BP.TRANSFERID
      INNER JOIN BCAS_INSURANCEPRODUCT BI ON BP.ID = BI.POLICYID
      WHERE BT.CREATINGDATE <= (SELECT SEL_DATE FROM SEL_WERTE)
  ) SEL ON BS.ID = SEL.STATEID
  LEFT OUTER JOIN
  (
    SELECT BP.POLICYID, SUM(BP."value") AS PAYMENT
      FROM BCAS_PAYMENT BP
      WHERE BP.BOOKINGDATE <= (SELECT SEL_DATE FROM SEL_WERTE)
      GROUP BY BP.POLICYID
  ) SEL2 ON SEL.ID = SEL2.POLICYID
GROUP BY BS.ID, BS."name"
ORDER BY BS.ID;

Wichtig ist es natürlich, den Monat bzw. das Datum in Zeile 1 anzupassen. Es ist immer das Datem des letzten Tages des Monats einzutragen.

Auswertung Tschechien.sql (12,46 kb)

UnitTestDetector

Gelegentlich benötigt man in seinem Code eine Fallunterscheidung, ob die aktuelle Ausführung unter Realbedingungen, oder im Rahmen von UnitTests läuft. Beispiel wäre die Auswahl eines Verzeichnisses, welches im Realbetrieb unterhalb des Webverzeichnisses, bei UnitTests aber z.B. in C:\Temp\ verwendet wird:

if (UnitTestDetector.IsInUnitTest)
  return string.Format("C:\\Temp\\");
else
  return string.Format(@"{0}\App_Data\", HttpRuntime.AppDomainAppPath);

Die zugehörige Klasse "UnitTestDetector" findet man im Anhang

UnitTestDetector.cs (562,00 bytes)

DBDok: Umwandeln und Übertragen von Dokumenten

Mittels des Befehlt DBDok_ToPDF.exe lassen sich Dokumente (TIFF) aus der Datenbank nach PDF umwandeln; mehrseitige Dokumente werden zusammengefasst und ins Archiv gespeichert.

Der Befehl akzeptiert verschiedene Parameter, die man in der Form /Parametername=Parameterwert anhängen kann und/oder in der zugehörigen .config-Datei hinterlegen kann:

  • ConnectionString = Datenbankverbindung zur Quelldatenbank. Hieraus werden die TIFFs gelesen
  • ConnectionStringDBDOK = Datenbankverbindung zur Zieldatenbank. Hierhin werden die PDFs geschrieben
  • Executable = Pfad zu Tiff2Pdf.exe, welches intern aufgerufen wird, um ein TIFF in eine PDF zu wendeln
  • WorkPath = Temporäres Arbeitsverzeichnis; Hier werden Arbeitsdateien zwischengelagert und eine Log-Datei fortgeschrieben
  • DocMax = Anzahl der Maximal zu verarbeitenden Dokumente je Aufruf
  • DocPerRun = Anzahl der zu verarbeitenden Dokumente je Durchlauf. Pro Durchlauf werden u.a. Datenbankverbindungen neu aufgebaut. Die ist notwendig, da es ansonsten mitunter zu Timeouts bei der Datenbankverbindung kommen kann.

 

Zusätzliche Tätigkeiten nach Update einer IWM Version

Nachdem das von IWM gelieferte Update eingespielt wurde,sind immer noch weitere Tätigkeiten notwendig, um unsere Individuellen Anpassungen zu übernehmen:

  • jtds-1.2.6.jar von C:\Temp\ nach C:\IWM\apache-tomcat-6.0.18\webapps\PortalNeu\WEB-INF\lib kopieren
  • kopieren aller Dateien unter C:\Sicherung\{Datum}\PortalNeu\jsf\hauptmaske\navigator nach C:\IWM\apache-tomcat-6.0.18\webapps\PortalNeu\jsf\hauptmaske\navigator
  • kopieren von anmeldung5.jsp aus C:\Sicherung\{Datum}\PortalNeu\jsf\anmeldung nach C:\IWM\apache-tomcat-6.0.18\webapps\PortalNeu\jsf\anmeldung
  • Abgleichen von C:\IWM\apache-tomcat-6.0.18\webapps\PortalNeu\user\user_config.xml mit der bisherigen Version unter C:\Sicherung\[Datum]\PortalNeu\user\user_config.xml. Dies muss mittels eines Texteditors, idealerweilse über ein Diff geschehen (Notepad++ ist hier z.B. gut geeignet). Fehlende Einträge müssen in die neue Datei übernommen werden; geänderte Einträge werden nicht korrigiert.
  • Das Verzeichnis C:\Sicherung\[Datum]\PortalNeu\user\ nach C:\IWM\apache-tomcat-6.0.18\webapps\PortalNeu\user\ überkopieren um bisherige Inhalte zu übernehmen. Bestehende Daten werden ersetzt

 

Connection refused

Sowohl auf dem Test- als auch auf dem Produktivsystem hatten wir mittlerweile einmal den Fehler, daß beim Aufruf eines beliebigen Fortuna-Tools im Navigator eine Fehlermeldung "Connection refused" erschien.

Grund dafür ist, daß der SSO-Service nicht aufgerufen werden kann. Warum dies so ist, ist nicht ganz sicher, vermutlich kann die URL nicht aufgelöst werden. Mit dem direkten Aufruf über die IP Adresse funktioniert das Ganze aber auch nicht. Was erst einmal hilft ist, die HOSTS-Datei unter C:\Windows\System32\drivers\etc um einträge zu erweitern, welche die URL des SSO Servers auflösen.

Hier sollte allerdings noch gemeinsam mit den Admins eine bessere Lösung gefunden werden, vermutlich muss man im Proxy/Reverse-Proxy entsprechende Einträge vornehmen.

Datenübernahme MV: Riester

Im TFS unter Fortuna/Tools/Fortuna.MuenchenerVerein/ExcelTrasition gibt es eine Solution Fortuna.MuenchenerVerein.ExcelTrasition. Hier gibt es Klassen zu Übernahme der Excel-Daten in eine Oracle Datenbank.

Die Excel-Dateien von MV sind im Projekt enthalten. Gibt es neue Daten, müssen diese ausgetauscht werden.

Ebenso enthalten ist ein Script zur Erzeugung der Datenbanktabellen.

Um die Daten zu Übernehmen gibt es eine ganze Reihe von Tests (zu sehen über den Testexplorer. Diese Test können/müssen einzeln oder en bloc ausgeführt werden. Die Ausführungszeit liegt bei ca. 30 Minuten (Stand September 2013)

 

Datenübername MV: OASIS/LIFE/COR_ADMIN

Im Rahmen des Projektes MV sind diverse Versicherungsdaten aus MV Systemen in myLife System zu übernehmen.

Tätigkeiten zur Übernahme von Personendaten:

OASIS, LIFE und COR_ADMIN werden benötigt. Das eigentliche 'Zusammentragen' der Daten geschieht auf Mig_MVR

Mig_MVR benötigt Zugriff auf COR_ADMIN, LIFE und OASIS:

-- Ausführen auf COR_ADMIN
select  'grant select on COR_ADMIN.'||object_name||' to Mig_MVR with Grant Option;'
from    all_objects 
where   object_type in ('VIEW','TABLE')
and     object_name not like 'BIN$%==$0'
and owner = 'COR_ADMIN'

UNION

select  'grant execute on COR_ADMIN.'||object_name||' to Mig_MVR with Grant Option;'
from    all_objects 
where   owner = 'COR_ADMIN'
and     object_name not like 'BIN$%==$0'
and object_type in ('FUNCTION', 'PROCEDURE', 'PACKAGE');


-- Ausführen auf OASIS
select  'grant select on OASIS.'||object_name||' to Mig_MVR with Grant Option;'
from    all_objects 
where   object_type in ('VIEW','TABLE')
and     object_name not like 'BIN$%==$0'
and owner = 'OASIS'

UNION

select  'grant execute on OASIS.'||object_name||' to Mig_MVR with Grant Option;'
from    all_objects 
where   owner = 'OASIS'
and     object_name not like 'BIN$%==$0'
and object_type in ('FUNCTION', 'PROCEDURE', 'PACKAGE');


-- Ausführen auf LIFE
select  'grant select on LIFE.'||object_name||' to Mig_MVR with Grant Option;'
from    all_objects 
where   object_type in ('VIEW','TABLE')
and     object_name not like 'BIN$%==$0'
and owner = 'LIFE'

UNION

select  'grant execute on LIFE.'||object_name||' to Mig_MVR with Grant Option;'
from    all_objects 
where   owner = 'LIFE'
and     object_name not like 'BIN$%==$0'
and object_type in ('FUNCTION', 'PROCEDURE', 'PACKAGE');

Die Ausgaben der Statements müssen wiederum jeweils auf den beschriebenen Servern ausgeführt werden.

Zusätzlich braucht Mig_MVR noch weitere Berechtigungen:

grant select on BANK to Mig_MVR with Grant Option;

Auf Mig_MVR werden anschliessend diverse Views angelegt (MYLIFE_Mig_MVR_VIEWS.sql (14,39 kb)).