Autor Beitrag
Vegeto
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Mo 07.07.14 15:12 
Hallo,

ich wollte über mein Programm eine DataTable in eine Tabelle in meiner Datenbank(SQL) schreiben, habe im Internet gelesen, dass dies mittels SqlBulkCopy, funktionieren sollte. Doch leider gibt er bei mir ein Fehler aus
Zitat:
Der angegebene Wert vom Typ String aus der Datenquelle kann nicht in Typ bigint der angegebenen Zielspalte konvertiert werden.

Ich kann den Fehler nachvollziehen, da alle meine Datensätze in dem Datatable string sind, aber auf der Datenbank haben die einzelnen Spalten andere Typen, in diesem Fall bigint.

Jetzt wollte ich euch fragen, gibt es eine Möglichkeit das DataTable in die Zieltaballe zu schreiben?

Das Datatable fülle ich über eine Schleife und kann leider dort nicht die einzelnen Spaltentypen mit angeben. Daher brauche ich einen WEG um diese Datensätze in die Zeiltabelle zu kopieren!

Ich hoffe Ihr könnt mir helfen.

Lg
Vegeto
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 07.07.14 16:05 
Normalerweise erfolgt die Konvertierung automatisch. Sicher das da nicht einfach Sachen in deinen daten sind die tatächlich kein BigInt sein können? Zum Beispiel Leerstrings? Was für SqlBulkCopyOptions benutzt du?
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Mo 07.07.14 16:19 
Hallo Ralf Jansen,

Ich benutze diese Options:
SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.FireTriggers | SqlBulkCopyOptions.UseInternalTransaction | SqlBulkCopyOptions.KeepNulls

Und ja du hast recht einige Felder haben leerstrings :/ ich dachte immer er übergibt sie dann als DBNULL-Wert weiter.

Wie kann ich den leerstrings als DBNullwert wieder geben?

Ich habe auch versucht:
Meinem DataTable die Spalten manuell zu erstellen (Int64, String), doch nun frage ich mich wenn der Datentyp in der Datenbank BigInt ist, aber dieser Kommazahlen entgegennehmen kann, welchen Typ muss ich verweden?

Dazu kommt wenn ich einer Spalte den Datentyp Int64 zuordne, doch dann ein leerstring kommt, dass er ein Fehler rauswirft, statt dort eine 0 oder NIX einzutragen, obwohl ich beim erstellen der ganzen Spalten erlaube das die Spalte DBNULL beinhalten darf.

Bitte um hilfe, weiß nicht mehr weiter :(

Lg
Vegeto
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 07.07.14 16:58 
Du könntest versuchen alle Leerstrings beim Füllen der DataTable als null reinzuschreiben:
ausblenden C#-Quelltext
1:
2:
if (String.IsNullOrWhitespace(str))
  str = null;

Für diesen Beitrag haben gedankt: Vegeto
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Mo 07.07.14 17:11 
Hi Th69,

habe ich gerade versucht, mit dem Code den du mir gegeben hast, trotzdem kommt der Fehler :(

Lg
vegeto
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 07.07.14 17:38 
Zitat:
Ich habe auch versucht:
Meinem DataTable die Spalten manuell zu erstellen (Int64, String), doch nun frage ich mich wenn der Datentyp in der Datenbank BigInt ist, aber dieser Kommazahlen entgegennehmen kann, welchen Typ muss ich verweden?


Ein BigInt der Kommazahlen annimmt bezweifle ich mal stark. Ein Komma wäre in SQL das Tausendertrennzeichen und der Punkt das Dezimaltrennzeichen.

Für diesen Beitrag haben gedankt: Vegeto
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Mo 07.07.14 18:06 
Hi Ralf,

du hast natürlich vollkomen Recht, habe falsch nachgegcukt.

Doch leider weiß ich nicht wie ich diese leeren Zellen des Datatables mit DBNULL oder allgemein null setzen kann :(

LG
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 07.07.14 18:14 
Erst gar nicht in die DataTable reinschreiben sondern gleich DBNull setzen? In etwa so wie es TH69 gezeigt hat.
Zeig doch mal deinen DataTable-Befüllungscode.

Für diesen Beitrag haben gedankt: Vegeto
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Mo 07.07.14 19:03 
Hallo Ralf Jansen,

also ich habe zunächst eine string variable, womit ich die einzelnen Zeilen meines Datatable fülle.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
// Dieser String beinhaltet alles was in eine Zeile rein soll, diese wird von einem Streamwriter befüllt, Trennzeichen sind '|'
// sollte mal eine Zelle nicht gefüllt sein bleibt sie Leer
// Bsp.: 48418757|85741872|587|1|2|1,89|Test Test||8484871125||
string ausgabe;

DataTable dt = new DataTable();

dt.Rows.Add(ausgabe.split('|'));


So wird eine Zeile zum Datatable hinzugefügt.
Wenn Ich nun von der letzten Spalte der Datentyp String mache, nimmt er das an, aber sobald ich das dann mittels SqlBulkCopy kopieren will sagt er halt kann nicht konvertiert werden. Doch wenn ich den Datentyp auf Int64 verändere sagt er mir der datentyp des DataTable ist falsch.

Lg
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 07.07.14 20:24 
Zeig mir mal den Code mit meiner vorgeschlagenen Veränderung drin (ich habe da so einen Verdacht...).

PS: Außerdem solltest du die Spalte in der DataTable dann zu Nullable<Int64> (bzw. in kurz Int64? (= long?) ändern.

Für diesen Beitrag haben gedankt: Vegeto
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 07.07.14 21:02 
ausblenden C#-Quelltext
1:
dt.Rows.Add(ausgabe.Split('|').Select(x=> !string.IsNullOrWhiteSpace(x) ? (object)x : DBNull.Value));					


Du solltest aber ein wenig mehr tun als string.Split
Wie 1,89 genau umgewandelt wird hängt von lokalen Systemeinstellungen ab auf die du dich nicht verlassen solltest.


Zuletzt bearbeitet von Ralf Jansen am Di 08.07.14 09:44, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: Vegeto
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Di 08.07.14 08:42 
Hallo Th69 und Ralf Jansen,
tut mir leid, dass ich gestern nicht mehr schreiben konnte, habe noch einiges probiert, aber es hat nicht funktioniert. Danach musste ich noch etwas erledigen. Ich werde mal die beiden Ansätze die Ihr mir gezeigt habt versuchen in mein Code einzubauen.

Sollte es nicht hin hauen, poste ich später meinen C#-Code.

Danke für euere Hilfe.

LG
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Di 08.07.14 10:31 
So, habe eure code snippets versucht einzubauen, leider kommt eine andere Fehlermeldung :(

Also zunächst einmal an Th69:

Mein Code zum erstellen von Datatable:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
// So füge ich ein DataColumn meinem Datatable zu
dtCol = new DataColumn();
dtCol.ColumnName = "height";
dtCol.AllowDBNull = true;
dtCol.DataType = typeof(Nullable<Int64>);
dt.Columns.Add(dtCol);

// Doch nun kommt die Fehlermeldung:
// DataSet unterstützt nicht System.Nullable<>.


Nun kommen wir zu Ralf Jansen :)

Mein Code zum füllen des DataTables:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
dt.Rows.Add(ausgabe.Split('|').Select(x=> !string.IsNullOrWhiteSpace(x) ? (object)x:DBNull.Value));
isNewRow = false;
ausgabe = "";

// ich setze die string ausgabe wieder auf ein Leerstring damit dieser wieder mittels schleife befüllt werden kann.

// Die Fehlermeldung hier ist:
/// Das Objekt des Typs "WhereSelectArrayIterator`2[System.String,System.Object]" kann nicht in Typ "System.IConvertible" umgewandelt werden.<System.Linq.Enumerable+WhereSelectArrayIterator`2[System.String,System.Object]> konnte nicht in der Spalte1-Spalte gespeichert werden. Erwarteter Typ: Int64. ---> System.InvalidCastException: Das Objekt des Typs "WhereSelectArrayIterator`2[System.String,System.Object]" kann nicht in Typ "System.IConvertible" umgewandelt werden.


Ich weiß leider nicht mehr weiter. :(

Wenn es eine anderen Weg gibt bin ich gerne offen für den, ich dachte mir nur das dieser am schnellsten ist(über SqlBulkCopy).

Lg
vegeto
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 08.07.14 10:37 
Wenn du den konkreten Typ je Spalte brauchst wird dir ein allgemeiner Ansatz wie der gezeigte mit string.Split nicht helfen. Das geht nur wenn auch alles string ist (oder genauer wenn am Ende alles vom gleichen Typ ist).

Wenn du je Spalte den konkreten Typ haben willst dann mußt du das auch je Spalte in den konkreten Typ umwandeln. Also splitten, jede Spalte im Array dann in den gewünschten Typ umwandeln (dann kannst du auch die Umwandlung des Doubles gleich richtig machen) und dann erst in eine DataRow packen.

Für diesen Beitrag haben gedankt: Vegeto
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Di 08.07.14 10:59 
Hallo Ralf Jansen,
ich habe jetzt einfach die SQL Spalte verändert -.- hatte keine Lust mehr... xD

Danke euch beiden, habe sehr viel Dank euch gelernt :)

Lg
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 08.07.14 11:13 
Hallo Vegeto,

sorry, das mit Nullable<Int64> war falsch. Du hast ja schon die richtige Eigenschaft dafür verwendet: AllowDBNull.
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Di 08.07.14 11:21 
Hallo Th69,

nicht weiter wild ;)

Aber nur aus reiner neugiere, gibt es den eine Möglichkeit?

Also dass er wenn die Zelle im Datatable Leer ist, dies zu einem DBNull.Value zu verändern?

Würde mich sehr Interessieren :)

Lg
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Di 08.07.14 12:40 
user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:

Wenn du je Spalte den konkreten Typ haben willst dann mußt du das auch je Spalte in den konkreten Typ umwandeln. Also splitten, jede Spalte im Array dann in den gewünschten Typ umwandeln (dann kannst du auch die Umwandlung des Doubles gleich richtig machen) und dann erst in eine DataRow packen.


Hi Ralf Jansen, wie kann ich den eine Spalte in einem Array nachträglich den Typen verändern?
Denn ich dachte immer es ist nur möglich ein Array ausschließlich von einem Datentyp zu erstellen Bsp.: int[] Array = new int{1,7...}; aber mir war nie bewusst, dass man dann den einzenen Array Spalten verändern kann.

Oder habe ich jetzt was falsch verstanden?

Wie kann ich den einfach beim füllen einer Zeile sagen, dass die leerstring als DBNull gespeichrt werden soll?

Lg
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 08.07.14 13:10 
Zitat:
Oder habe ich jetzt was falsch verstanden?


Nein du vergisst nur das Konzept von Ableitung. In einem Array vom Typ X können nur X'e und Ableitungen von X sein. Wenn du dir mein Beispiel zum befüllen mit einem Array nochmal ansiehst solltest du erkenne das ich da keine Liste von strings reinfülle sondern eine vom Typ Object (weil DBNull nun mal kein string ist sondern ein eigener Typ) und in einem Object Array kann alles stecken da alles von Object ableitet also auch strings und DBNull.

Im folgenden knallt es dann weil Object nicht nach Int64 konvertierbar ist (Object implementiert noch nicht IConvertible, jeder Typ hat eine ToString und kann immer nach string konvertiert werden darum hat man bei strings so ein Problem nicht).

Es typisiert zu machen ist richtig aber den Shortcut um sich eine DataRow zu erzeugen ist reines "Programming by Surprise". Ach gucken wir mal was am Ende da wohl an Konvertierung rauskommt. Du solltest kein Glücksspiel betreiben.

Erzeuge eine neue DataRow, nimm den jeweiligen Wert aus dem gesplitteten Array, konvertiere ihn in den richtigen Zieltyp der in der Spalte der Row erwartet wird (unter Berücksichtigung des Formats in der csv Datei, ich erwähne hier explizit noch mal den Double Wert!) und dann füge die Row der DataTable hinzu. Das ist ein wenig mehr Code als der bisherige Einzeiler aber so hast du dann jetzt endlich die nötige Kontrolle was denn tatsächlich passiert und kommst ohne Überraschungen ans Ziel.
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: Di 08.07.14 13:28 
Hallo Ralf Jansen,

danke für deine Antwort, ich werde mich mal ran machen. Bei Problem, schreibe ich es hier auf.

Danke

Edit:
Ich gehe nun so voran:
Ich splitte meine ausgabe, lese jeden wert aus und konvertiere ihn in die gewünschten Datentyp, sollte dieser NullorEmpty sein soll er DBNULL entgegen nehmen.
Das dann in das DT einfügen.