AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Set of Enumeration Type in Datenbank-Parameter zuweisen
Thema durchsuchen
Ansicht
Themen-Optionen

Set of Enumeration Type in Datenbank-Parameter zuweisen

Ein Thema von DelphiBandit · begonnen am 10. Jun 2014 · letzter Beitrag vom 12. Jun 2014
Antwort Antwort
Benutzerbild von DelphiBandit
DelphiBandit

Registriert seit: 19. Feb 2007
Ort: bei Walsrode
165 Beiträge
 
Delphi 10.4 Sydney
 
#1

Set of Enumeration Type in Datenbank-Parameter zuweisen

  Alt 10. Jun 2014, 13:14
Delphi-Version: XE5
Hallo zusammen,

ich habe eine vermutlich ganz triviale Frage. Der Laufzeitfehler bezüglich Typkonvertierung beschäftigt mich allerdings schon eine Weile, ohne dass ich bisher eine Lösung gefunden hätte.

Delphi-Quellcode:
type
  TBankFlag = (fbfEinzahlung, fbfAuszahlung);
type
  TBankFlags = set of TBankFlag;

// Diese in im Objekt als Property vorhanden
type
  TFoo = type(TObject)
    FFlags: TBankFlags;
  published
    Flags: TBankFlags read FFlags write FFlags;
  end;
Den Wert bestimme ich per RTTI und bekomme einen Wert vom Typ TValue zurück. Jetzt möchte ich diesen in der Datenbank als Integer speichern. Dabei kommt aber immer ein Laufzeitfehler "Ungültige Typumwandlung", obwohl ich in value.AsInteger den korrekten Wert im Debugger sehen kann. Das Feld Flags ist in der Datenbank als Integer angelegt.

foo.Flags := [fbfEinzahlung, fbfAuszahlung] -> value.AsInteger = 3
foo.Flags := [fbfEinzahlung] -> value.AsInteger = 1

Delphi-Quellcode:
..
var value: TValue;
begin
  // ...value-Bestimmung...
  
  qry.ParamByName('FLAGS').AsInteger := value.AsInteger;
end;
Egal welchen Typ ich mir von TValue mit .AsXXX geben lasse, es knallt beim Zuweisen dieses Parameters. Noch eine Anmerkung, Flags kann je nach Objekt verschiedene ENum-Bedeutungen haben. Also ist AsType<T> für mich nicht so zielführend.

Geht das überhaupt, was ich da vorhabe?
Carsten

Geändert von DelphiBandit (10. Jun 2014 um 13:22 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.115 Beiträge
 
Delphi 12 Athens
 
#2

AW: Set of Enumeration Type in Datenbank-Parameter zuweisen

  Alt 10. Jun 2014, 13:19
Früher hat man das so gemacht:
  qry.ParamByName('FLAGS').AsInteger := Byte(value);
Ein Set ist nunmal kein "ordinaler" Typ.

Oder du gehst über die RTTI und wandelst das in einen String um.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#3

AW: Set of Enumeration Type in Datenbank-Parameter zuweisen

  Alt 10. Jun 2014, 13:32
Hallo,

Hab grad rumprobiert und hatte auch so meine Probleme, aber so gehts:

Delphi-Quellcode:
var b: Byte;
begin
  // ...
  value.ExtractRawData(@b);
  qry.ParamByName('FLAGS').AsInteger := b;
  // ODER
  qry.ParamByName('FLAGS').AsInteger := PByte(value.GetReferenceToRawData)^;
end;
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."

Geändert von Neutral General (10. Jun 2014 um 13:36 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther
Online

Registriert seit: 6. Mär 2013
6.110 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: Set of Enumeration Type in Datenbank-Parameter zuweisen

  Alt 10. Jun 2014, 13:38
Ich würde es als String in die Datenbank speichern. Wenn da später jemand draufguckt, könnte man noch eine ungefähre Vorstellung dafür bekommen, was das ist.

Abgesehen davon- Kannst du deinem Enum nicht eine Helfer-Methode verpassen?

Delphi-Quellcode:
type
   TMeinEnum = (Hund, Katze, Maus);

   TMeinEnumHelper = record helper for TMeinEnum
      function ToString(): String;
      function ToInteger(): Integer;
      // function ToField(): TField // oder so ähnlich?
   end;
   
implementation uses System.TypInfo;

function TMeinEnumHelper.ToString(): String;
begin
   Result := GetEnumName(
      TypeInfo(TMeinEnum), // Den Namen hier nochmal manuell zu nennen muss wohl...
      Ord(self)
   );
end;

function TMeinEnumHelper.ToInteger(): Integer;
begin
   Result := Ord(self);
end;
  Mit Zitat antworten Zitat
Benutzerbild von DelphiBandit
DelphiBandit

Registriert seit: 19. Feb 2007
Ort: bei Walsrode
165 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Set of Enumeration Type in Datenbank-Parameter zuweisen

  Alt 10. Jun 2014, 14:02
Danke für die superschnelle Hilfe, ich werde für den Moment mal mit Michaels Ansatz weiterarbeiten.

Das mit der Helper-Klasse hätte ich wohl schon gemacht, wenn im rechten Teil des Helpers auch ein generischer Typ angegeben werden könnte Ich habe bisher drei unterschiedliche Typen von "FLAGS", je nachdem in welchem Objekt. Und jedem Set sein eigenes Helper-Objekt an die Seite zu stellen mit dreimal dem gleichen Quellcode bis auf den Typ

Die Überlegung das Ganze in Strings in die Datenbank zu speichern ist gut, erschwert aber nachher die Suche. Mit dem Integer brauche ich nur mit logischem AND eine Bitposition in FLAGS abfragen. So war zumindest meine Grundüberlegung.

Aber wenn ich so drüber nachdenke, könnte ich das ganze Set auch in eigenes Objekt verschieben und mit einzelnen boolschen Property-Werten arbeiten. Macht den Quellcode lesbarer, aber die nachfolgende Speicherung und Suche auch nicht gerade übersichtlicher.
Carsten
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#6

AW: Set of Enumeration Type in Datenbank-Parameter zuweisen

  Alt 10. Jun 2014, 16:48
Eine Alternative und von den Restriktionen des ENUM-SET gänzlich unabhängige Variante wäre die, die einzelnen Ausprägungen des Enums in eine Tabelle zu packen und eine n:m-Beziehung zwischen dem Objekt und der Enum-Tabelle zu erstellen.

Das ist eine allgemeingültige Lösung, die vollständig im DB-Schema dokumentiert ist und die es erlaubt, sehr einfach Queries zu erstellen, ohne im Code zu schauen, wie den das SET nun kodiert wurde.

Einfach ausgedrückt:
Tabelle 'Enum'
IdName
1Rot
2Grün
3Blau
Tabelle 'Daten'
IdName
10Meyer
11Müller
12Schulz
Tabelle 'DatenEnums'
IdEnumIdDaten
110
211
311
Meyer ist rot und Müller ist grün und blau.
  Mit Zitat antworten Zitat
Benutzerbild von smallie
smallie

Registriert seit: 8. Jan 2013
17 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: Set of Enumeration Type in Datenbank-Parameter zuweisen

  Alt 12. Jun 2014, 22:35
Das mit der Helper-Klasse hätte ich wohl schon gemacht, wenn im rechten Teil des Helpers auch ein generischer Typ angegeben werden könnte Ich habe bisher drei unterschiedliche Typen von "FLAGS", je nachdem in welchem Objekt. Und jedem Set sein eigenes Helper-Objekt an die Seite zu stellen mit dreimal dem gleichen Quellcode bis auf den Typ
Ich mach' das so:

Delphi-Quellcode:
uses
  TypInfo;

type
  TEnumHelper = class
  private
    FEnumInfo: PTypeInfo;
  public
    Constructor Create(AEnumInfo: PTypeInfo);
    function ToString(const EnumValue): string; //typloser Parameter
    function ToEnum(const Name: string): integer;
  end;


implementation

constructor TEnumHelper.Create(AEnumInfo: PTypeInfo);
begin
  FEnumInfo := AEnumInfo;
end;

function TEnumHelper.ToString(const EnumValue): string;
begin
  Result := GetEnumName(FEnumInfo, ord(TOrdType(EnumValue))); //typloser Parameter wird gecastet
end;


function TEnumHelper.ToEnum(const Name: string): integer;
begin
  Result := GetEnumValue(FEnumInfo, Name);
end;
So läßt sich damit arbeiten:

Delphi-Quellcode:
//Enumeration:
TTasteBuds = (tbSour, tbSweet, tbSalty, tbSpicey, tbUmami)

//Erzeugung und Verwendung
TasteBuds := TEnumHelper.Create(TypeInfo(TTasteBuds));
showMessage(TasteBuds.ToString(tbSour)); //"tbSour"

//oder andere Richtung
var SomeTasteBud: TTasteBuds;

SomeTasteBud := TTasteBuds(TasteBuds.ToEnum(tbSour)); //hier muß zurückgecastet werden. :(
Auf eine Lösung, wie ich diesen letzten Cast einsparen kann, bin ich noch nicht gekommen. Wenn nur eine Zahl herauskommen soll, passt es.
"There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors."
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.115 Beiträge
 
Delphi 12 Athens
 
#8

AW: Set of Enumeration Type in Datenbank-Parameter zuweisen

  Alt 12. Jun 2014, 23:24
Nja, es geht auch andersrum.


Byte(SomeTasteBud) := TasteBuds.ToEnum(tbSour);

oder
Delphi-Quellcode:
var
  SomeTasteBudByte: Byte absolute SomeTasteBud;

SomeTasteBud := TasteBuds.ToEnum(tbSour);

Oder du definierst das TEnumHelper.ToEnum als Prozedur und gibst das Result ebenfalls als typlosen VAR/OUT-Parameter raus, genauso wie beim CONST.



Wenn du dir in den letzten paar 5 Jahren mal ein neueres Delph zugelegt hättest, dann ginge auch sowas.

Delphi-Quellcode:
RTTIServices = class
  class function SetToStr<TSet>(const Value: TSet; Brackets: Boolean=True): string; static;
  class function StrToSet<TSet>(const Value: string): TSet; static;

  class function EnumToStr<TEnum>(const Value: TEnum): string; static;
  class function StrToEnum<TEnum>(const Value: string): TEnum; static;
end;



var
  S: string;
  E: TTasteBuds;

S := RTTIServices.EnumToStr<TTasteBuds>(tbSour);
E := RTTIServices.StrToEnum<TTasteBuds>('tbSour');
Das entspricht in etwa deinem Code, wenn man den Typ direkt mit übergibt
Delphi-Quellcode:
ShowMessage(TasteBuds.ToString(TypeInfo(TTasteBuds), Ord(tbSour))); // 'tbSour'

SomeTasteBud := TTasteBuds(TasteBuds.ToEnum(TypeInfo(TTasteBuds), 'tbSour')); // tbSour


Es liese sich im Aufruf nochmal etwas kürzen, wenn man den generischen Typ nicht an die Methoden, sondern an die Klasse bindet.
Delphi-Quellcode:
type
  EnumService<TEnum> = class
    class function EnumToStr(const Value: TEnum): string; static;
    class function StrToEnum(const Value: string): TEnum; static;
  end;

type
  X = EnumService<TTasteBuds>;

var
  S: string;
  E: TTasteBuds;

S := EnumService<TTasteBuds>.EnumToStr(tbSour);
E := EnumService<TTasteBuds>.StrToEnum('tbSour');

S := X.EnumToStr(tbSour);
E := X.StrToEnum('tbSour');



Und nein, TOrdType ist nicht immer richtig.
Eigentlich msstest du aus dem TypeInfo die Enum-Größe auslesen und dann entweder nach Byte, Word oder Integer casten,
denn wenn dein ENUM mehr als 256 Werte enthält, dann hast du ein Problem.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von Daniel (20. Nov 2014 um 07:06 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:51 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz