| 

.NET C# Java Javascript Exception

0
Hallo,

wir haben einen selbstgeschriebenen OR-Mapper für unsere Datenbank. Realisiert ist das ganze in C# mithilfe von Klassen, welche die Datenbankstruktur wiederspiegeln. D.h. es gibt für jede Tabelle eine Klasse und übergeordnet ein Dictionary, welches die einzelnen Objekte hält. Diese werden dann über einen generischen Mechanismus aus der Datenbank befüllt, bzw in die Datenbank geschrieben.
organisiert sind diese Klassen in einem eigenen Namespace (DBClassesDB25).
Der Mapper hängt gerade noch auf unserer internen Datenbankversion DB25 fest. Nun haben sich Änderungen ergeben, woraus sich Version 26 und 27 entwickelt haben, welche alle bei verschiedenen Kunden im Einsatz sind.
Ich suche nun eine Möglichkeit um mehrere Versionen meiner Klassen in einer Anwendung zu halten, ohne beim Lesen/Schreiben immer zu überprüfen ob ein Feld nun zu DB25, DB26 oder DB27 gehört.

Hat da eventuell jemand eine Idee?

Beste Grüße
Barados
News:
09.10.2013
Barados 288 1 7
3 Antworten
1
Eine Möglichkeit wäre es das ganze über Attibute zu lösen die die Datenbankversion angeben. In der generischen Funktion die die Objekte befüllt kannst du dann die Attribute auslesen. Das ganze ist aber nicht sehr performant wenn man sehr viele Felder verarbeitet, da die Attribute über Reflection ausgelesen werden. Besser wäre es mittels PostSharp oder einem anderen AOP-Framework den Code durch die Attribute direkt umschreiben zu lassen. Dadurch hast du wieder die volle Performance weil du nicht auf Reflection zurückgreifen musst.

Eine andere alternative wäre T4-Vorlagen oder Pre-Compiler-Konstanten zu verwenden. Beide führen dazu das du verschiedene Versionen der Klasse erzeugst.

Beispiel Pre-Compiler:

#if DB25 or DB26 or DB27
public string Feld1 {get; set;}
public string Feld2 {get; set;}
#end if
#if DB26 or DB27
public string Feld3 {get; set;}
#end if
#if DB27
public string Feld4 {get; set;}
#end if


Nachtrag

Bezogen auf deinen zweiten Beitrag aus dem hervorgeht das du die Klassen für dein ORM mittels SQL erzeugst möchte ich das Konzept der Attribute mal auf die Datenbank übertragen. Ich weiß leider nicht welche Datenbankengine du verwendest aber zum Beispiel gibt es bei MSSQL so genannte extended Properties. Standardmäßig hat jedes Feld einer Tabelle Eigenschaften wir den Datentyp, Beschreibung, Allow NULLs, Primary Key, Is Computed, Identity, Identity Seed, .....
Du kannst zudem auch eigene Properties hinzufügen um zum Beispiel deine Datenbankversion darin abzulegen.

EXEC sys.sp_addextendedproperty 
@name = N'Min_DB_Version',
@value = N'96',
@level0type = N'SCHEMA', @level0name = dbo,
@level1type = N'TABLE', @level1name = tblProduct,
@level2type = N'COLUMN', @level2name = a_MyColumn;
GO

Dieses Stück Code fügt das Property 'Min_DB_Version', der Spalte 'a_MyColumn' in der Tabelle 'dbo.tblProduct' hinzu.

Über die Funktion 'fn_listextendedproperty' kannst du im anschluss die Properties wieder auslesen.

Das ist nur ein sehr einfaches Beispiel was mit Extended Properties alles möglich ist. Properties können übrigens auf so ziehmlich jedes Datenbank-Objekt gelegt werden. dh. auch auf Tabellen, Schemas, Nutzerrollen, Datenbanken, .....

Mehr dazu unter:

Using Extended Properties on Database Objects
sp_addextendedproperty (Transact-SQL)
fn_listextendedproperty (Transact-SQL)
09.10.2013
Floyd 14,6k 3 9
Floyd 14,6k 3 9
Die Pre-Compiler Sache ist echt gut. Ich denke das werde ich mir mit merken.
Barados 10.10.2013
0
Ich habe jetzt mittels reinem SQL eine erste funktionierende Version, welche auch die bisherigen Anforderungen abdeckt...

Ich stell das einfach mal zur Diskussion:

unsere Tabellen heissen alle "gptbl_[objecttype]_[subobjecttype][...]"

SET NOCOUNT ON

declare @queriedtablenames table(ID NVARCHAR(200) PRIMARY KEY NOT NULL, processed int)
insert into @queriedtablenames
SELECT distinct [TABLE_NAME], 0 as processed
FROM [INFORMATION_SCHEMA].[TABLES]
order by TABLE_NAME


While (Select Count(*) From @queriedtablenames Where processed = 0) > 0
BEGIN

declare @class varchar(max);
declare @classname varchar(max);
declare @tablename varchar(max);
declare @tablestring varchar(max);
declare @keycolumns varchar(max);
declare @keycolumnsstring varchar(max);

Select Top 1 @tablename = ID From @queriedtablenames Where processed = 0

-- set @tablename = 'gptbl_material_routing'
set @classname = REPLACE(@tablename, 'gptbl_','');
-- set @classname = UPPER(SUBSTRING(@classname, 1, 1)) + SUBSTRING(@classname,2,LEN(@classname)-1);
set @tablestring = 'public override String table { get { return "' + @tablename + '"; } }'

select @keycolumns =
isnull(@keycolumns, '') +
column_name + ','
from information_schema.columns sc
where table_name = @tablename and IS_NULLABLE = 'NO'

set @keycolumnsstring = 'public override String keyColumns { get { return "' + SUBSTRING(@keycolumns, 1, LEN(@keycolumns)-1) +'"; } }'

; with typemapping as (
Select 'nvarchar' as DATA_TYPE, 'String' ctype
union
Select 'int', 'int'
union
Select 'datetime', 'DateTime'
union
Select 'float','double'
)

select @class =
isnull(@class + char(10), '') +
'public ' + tm.ctype +
case
when sc.DATA_TYPE = 'nvarchar' then ''
else '?'
end +
CHAR(9) + column_name + -- UPPER
' { get { return (' + tm.ctype +
case
when sc.DATA_TYPE = 'nvarchar' then ''
else '?'
end +
')properties["' + column_name + '"];}' +
' set { properties["' + column_name + '"] = value; } }'
from information_schema.columns sc
inner join typemapping tm on sc.data_type = tm.data_type
where table_name = @tablename

set @class ='// Definition der Klasse ' + @classname + CHAR(13) +
'public class ' + @classname + ' : IGPObject' + CHAR(13)+ '{' + CHAR(13)+
+ @tablestring + CHAR(13)
+ @keycolumnsstring + CHAR(13) + CHAR(13)
+ @class + CHAR(13)
+ '}' + CHAR(13) + CHAR(13)
print @class
set @class = '';
Update @queriedtablenames Set processed = 1 Where ID = @tablename
END
10.10.2013
Barados 288 1 7
Sehe ich das richtig, das du mittels eines SQL-Statements die Klassen für dein ORM erstellst?
Hmmm, ein durchauch praktikabler weg, wobei ich persönlich wohl lieber T4-Vorlagen verwendet hätte aber das ist Geschmackssache.

Ich bearbeite meinen Beitrag einmal.
Floyd 10.10.2013
Ja ich erstelle damit die Klassen, und später noch mehr.
Barados 10.10.2013
Beitrag bearbeitet
Floyd 10.10.2013
0
So ganz verstehe ich die Organisation noch nicht. Soll jeder Kunde irgendwann die Version 27 bekommen oder sind das nur Anpassungen für den "speziellen" Kunden?
Wenn erstens würde ich auch die Produkte versionieren. Und jede Version kann nur auf auf die jeweilige DB zugreifen. Bei zweitens würde ich es für "spezielle" Kunden abstrahieren.
Aber vllt. hab ich das Problem auch nicht richtig verstanden!?
10.10.2013
Das Tool existiert für verschiedene Datenbankversionen. Ich suche halt nach einem Weg mir die Klassen automatisch zu erstellen (den hab ich ja nun) und dann weitere Änderungen einfach hinzufügen zu können. Da gefällt mir die Idee mit den Pre-Compiler Befehlen echt gut...
Barados 10.10.2013
Nachtrag: es gibt keine kundenspezifischen Datenbanken. Da habe ich mich falsch ausgedrückt. Verschiedene Kunden haben unterschiedliche Versionen im Einsatz. Bei mehreren ist es noch die DB25, bei einigen die DB26 und ab November soll deckend DB27 angewandt werden.
Barados 10.10.2013

Stelle deine .net-Frage jetzt!