Laden...

Forenbeiträge von dahaack Ingesamt 47 Beiträge

27.10.2012 - 20:41 Uhr

Hallo xxMUROxx,

danke für den Hinweis! Werd mir das ganze mal anschauen.

Viele Grüße

21.10.2012 - 19:48 Uhr

Hallo vbprogger,

handelt es sich hierbei denn tatsächlich um ein Grundlagenproblem?

Dass bei einer "sinnvollen" Abfrage, bei der Daten aus mehreren Tabellen zusammengefügt werden, der JOIN Befehl benutzt werden muss, ist mir auch klar.

Meine Tabelle hat ja eine variable Anzahl an Spalten, daher seh ich erstmal keine andere Möglichkeit, als mit einer übergeordneten Programmiersprache den Befehl zusammenzubasteln. Dies würde wohl in etwa so aussehen:

string[] columnNameArray = Mysql.SelectStringArray("select columnName from t_Column");
string query = "SELECT columnName as '"+ columnNameArray[0] + "'";
for(int i=1;i<columnNameArray.Count;i++)
{
    query += ", columnName as '"+ columnNameArray[i] + "'"
}
query += " from t_Cell";

Nun müsste ich ja nochmal jede einzelne Spalte in SQL durchgehen. Keine Ahnung, ob das überhaupt geht.

Ich habe den kompletten Befehl schon mithilfe von C# gelöst, indem ich einfach jede einzelne Spalte und darin wieder jede einzelne Zeile durchgegangen bin, und mir die entsprechende Zelle rausgeholt habe. Dieser Algorithmus dauert jedoch Ewigkeiten.

Meine Hoffnung war, dass jemand einen Indianertrick kennt, mit dem man das ganze mit deutlich weniger Rechenaufwand lösen kann.

15.10.2012 - 19:40 Uhr

Datenbanksystem: MySQL

Hallo,

ich habe wie in der überschrift genannt eine Tabelle mit variabler Zeilen- und Spaltenanzahl und verschiedenen Zellenelementen. Es gibt über 100 Spalten und 100 Zeilen.

Diese Tabelle wird aus 3 Tabellen zusamengebastelt. Hier eine vereinfachte Version:

create table t_Row
(
    rowId int unsigned not null auto_increment,
    rowName varchar(30),
    primary key(rowId)
);

create table t_Column
(
    columnId int unsigned not null auto_increment,
    columnName varchar(30),
    primary key(columnId)
);

create table t_Cell
(
    cellId int unsigned not null auto_increment,
    columnId int unsigned not null,
    rowId int unsigned not null,
    cellContent varchar(30),
    cellProperty varchar(30),
    foreign key(columnId) references t_Column(columnId),
    foreign key(rowId) references t_Row(rowId),
    primary key(cellId)
);

Es gibt jedoch nicht für jede Zelle auch einen Eintrag. Es gibt zum Beispiel 2 Zeilen, 2 Spalten, jedoch nur 3 Zelleninhalte:

insert into t_Row(rowName) values ('Row 1');
insert into t_Row(rowName) values ('Row 2');

insert into t_Column(columnName) values ('Column 1');
insert into t_Column(columnName) values ('Column 2');


insert into t_Cell(rowId, columnId, cellContent, cellProperty)
values(1, 1, 'Content 1,1', 'Property 1,1');

insert into t_Cell(rowId, columnId, cellContent, cellProperty)
values(2, 1, 'Content 2,1', 'Property 2,1');

insert into t_Cell(rowId, columnId, cellContent, cellProperty)
values(2, 2, 'Content 2,2', 'Property 2,2');

Nun möchte ich per Abfrage die eigentliche Tabelle erhalten (es reicht erstmal nur den 'Content' oder nur die 'Property' anzuzeigen). Nicht vorhandene Einträge sollen den Wert NULL bekommen.

Leider waren SQL Abfragen noch nie mein Fachgebiet, und ich hoffe, dass mir jemand von Euch bei diesem Problem weiterhelfen kann.

Die vermutlich ersten 4 Wörter der Abfrage kenne ich jedoch bereits:

select cellContent from t_Cell

Wie es jedoch dann mit dem LEFT JOIN, EQUI JOIN, sonstwas JOIN und sonsitgen Tricksereien und Unterabfragen weitergeht, weiß ich nicht.

Das Ergebnis sollte also etwa so aussehen:

'Content 1,1'     NULL
'Content 2,1'     'Content 2,2'

Vielen Dank im Voraus!

26.08.2012 - 22:46 Uhr

Hallo michlG,

ich denke nein. Bei dem einfachen Join wird ja auch die 100 angezeigt. Ich habe es jetz so gelöst, dass ich erst alle Werte raushole, und dann diejenigen rausschmeisse, bei denen das count(t_A.id) (mit score = [dem jeweiligen score aus der ersten Suche]) ist.

26.08.2012 - 17:21 Uhr

Hallo,

ich habe folgende Tabellen und Einträge gegeben:

create table t_A
(
	id int unsigned not null auto_increment,
	name char(30),
	primary key(id)
);

create table t_B
(
	id int unsigned not null auto_increment,
	aId int unsigned not null,
	score int,
	foreign key (aId) references t_A(id),
	primary key(id)
);

insert into t_A(name) values('Eintrag 1');
insert into t_A(name) values('Eintrag 2');

insert into t_B(aId,score) values(1,50);
insert into t_B(aId,score) values(2,50);
insert into t_B(aId,score) values(1,100);

Nun suche ich alle scores der Tabelle B, wenn dieser score auf jeden Eintrag in Tabelle A zeigt. In diesem Beispiel gibt es in B einen score von 50, der auf "Eintrag 1" zeigt, und einen score von 50, der auf "Eintrag 2" zeigt. Der score 100 zeigt nur auf "Eintrag 1".

Das Suchergebnis sollte in diesem Fall also eine Zeile mit dem Wert 50 sein. Ich hoffe ich habe es verständlich genug ausgedrückt.

Wie sieht diese Abfrage in SQL aus? Ist das ohne einer Funktion überhaupt möglich?

Vielen Dank!

19.07.2012 - 18:20 Uhr

Hallo gfoidl,

danke für die Antwort. Damit werd' ich's bestimmt schaffen.

18.07.2012 - 19:46 Uhr

Es kann doch nicht sein, dass es so schwierig ist rauszufinden, wie man die Temperatur der Grafikkarte ausliest.

Ich habe es auch mit WMI probiert:

WqlObjectQuery wqlQuery =
            new WqlObjectQuery("SELECT * FROM Win32_TemperatureProbe");
            ManagementObjectSearcher searcher =
                new ManagementObjectSearcher(wqlQuery);
            dataGridView1.Rows.Clear();
            int i = 0;
            foreach (ManagementObject disk in searcher.Get())
            {
                dataGridView1.Rows.Add();
                dataGridView1[1, i].Value = (disk.ToString());
                i++;
            }

Die Abfrage gibt keine Temperatur zurück. Dass das Programm "funktioniert", sehe ich daran, dass meine Laufwerke angezeigt werden, wenn ich Win32_TemperatureProbe mit Win32_LogicalDisk austausche.

Vielleicht hat ja doch noch jemand eine Idee? Dass es möglich sein muss, sehe ich an dem Programm Everest. Dort wird die Temperatur der Grafikkarte angezeigt.

16.07.2012 - 21:49 Uhr

Hallo,

danke für eure Antworten!

Wenn ich auf die Datei direkt verweise, kommt die Fehlermeldung > Fehlermeldung:

Es konnte kein Verweis auf "nvcpl.dll" hinzugefügt werden. Stellen Sie sicher, dass auf die Datei zugegriffen werden kann und dass sie eine gültige Assenbly oder COM-Komponente ist.

Die Lösung des Problems soll eben die Variante sein, die ich gewählt habe. *.dll Funktioniert nicht?

Wenn ich die Datei mit Dependency Walker öffne, so, gibt das Programm aus, dass die Datei IESHIMS.DLL nicht gefunden wurde.

Diese ist in der Aufrufhierarchie ind NVCPL.DLL => SHELL32.DLL => SHDOCVW.DLL => IEFRAME.DLL => IESHIMS.DLL

Wenn ich nach dieser Datei auf meinem Computer suche, habe ich wieder mehrere Suchergebnisse. Ich habe eine dieser Dateien in den System32 Ordner kopiert (wo er diese Datei vermisst hat) und die DLL neu geöffnet. Nun kommt die Fehlermeldung > Fehlermeldung:

Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.

Wenn ich es richtig einschätze dürfte ich eine nicht passende IESHIMS.DLL kopiert haben. Ist das richtig?

Das C# Programm gibt immer noch einen Fehler in der Funktion zurück.

16.07.2012 - 20:07 Uhr

Hallo liebe Gemeinde,

ich möchte für meinen Grafikkartenlüfter (NVIDIA Grafikkarte) eine Regelung programmieren.

Ich scheitere leider dabei die Temperatur der Grafikkarte auszulesen.

Nach einiger googelei fand ich heraus, dass eine Datei "nvcpl.dll" eingebunden werden muss.

Auf meinem Computer habe ich mehrere dieser Dateien gefunden, ich habe die genommen, welche im Windows/System32 Ordner vorhanden ist und in mein Projekt kopiert.

Google gibt bei verschiedenen Suchergebnissen übereinstimmend etwa folgenden Code aus:

private class NativeMethod
        {
            [DllImport("C:\\Windows\\System32\\nvcpl.dll", EntryPoint = "NvCplGetThermalSettings", CallingConvention = CallingConvention.Cdecl)]
            public static extern bool NvCplGetThermalSettings(int nWindowsMonitor, out int pdwCoreTemp, out int pdwAmbientTemp, out int pdwUpperLimit);
        }
        public void getTemperature()
        {
            if (NativeMethod.NvCplGetThermalSettings(1, out kern, out außen, out max))
            {

                dataGridView1[2, 0].Value = kern.GetTypeCode(); // Print temperature in datagridview
            }
            else
            {
                // Fehler
            }
        }

Nun habe ich die Möglichkeit in den Projektoptionen als Zielplattfrm "x86", "x64"oder "Any CPU" einzustellen. (Auf meinem Computer läuft Windows 7 64 Bit)

Wähle ich als Zielplattform x86 so stürzt das Programm ab: > Fehlermeldung:

Es wurde versucht, eine Datei mit einem falschen Format zu laden. (Ausnahme von HRESULT: 0x8007000B)

Stelle ich die Zielplattform auf Any CPU oder x64, so stürzt das Programm zwar nicht ab, allerdings erhalte ich auch keine Temperatur, weil die Methode

NativeMethod.NvCplGetThermalSettings(1, out kern, out außen, out max)

false zurückgibt, was bedeutet, dass ein Fehler aufgetreten ist.

Leider findet man aber auch in der Beschreibung der DLL keinerlei Infos über die Ursache des Fehlers. http://developer.download.nvidia.com/SDK/9.5/Samples/DEMOS/common/src/NvCpl/docs/NVControlPanel_API.pdf (Seite 64)

Auch bei google habe ich nichts gefunden. Hat jemand vielleicht einen Tipp für mich?

Danke!

27.10.2011 - 21:48 Uhr

Okay, hat sich erledigt.

CREATE FUNCTION f_IsActualUserName ( userId INT UNSIGNED, userName CHAR(48), nameStartDate DATETIME )
RETURNS BOOL
BEGIN
	DECLARE date DATETIME;
	DECLARE name CHAR(48);

	SELECT MAX(tableUserName.startDate)
	FROM tableUserName
	WHERE tableUserName.userId = userId
	INTO date;

	IF date != nameStartDate THEN
		RETURN FALSE;
	END IF;

	SELECT tableUserName.name
	FROM tableUserName
	WHERE tableUserName.startDate = date
	AND tableUserName.userId = userId
	INTO name;

	RETURN userName = name;
END;


CREATE VIEW v_User AS
	SELECT tableUserName.name, tableUsername.startDate, tableUserName.userId
	FROM tableUserName, tableUser
	WHERE tableUserName.userId = tableUser.id
	AND f_IsActualUserName(tableUserName.userId, tableUserName.name, tableUserName.startDate);

Danke an alle!

Grüße

dahaack

27.10.2011 - 00:50 Uhr

Hallo Coder,

der obige Befehl

INSERT INTO tableUserName(userId, name, startDate)
SELECT tableUserName.id, 'Neuer Benutzer', Now()
FROM tableUserName
WHERE tableUserName.name = 'Benutzer 2'

funktioniert ja bereits, und viel eleganter kann man das glaube ich nicht machen. Daher ist das Problem ja sowieso gelöst. Du hast wahrscheinlich recht, dass eine Variablendeklaration an dieser Stelle nicht möglich ist.

Ich hab nochmal eine allgemeine Frage zu den beiden Tabellen. Ich möchte eine VIEW erstellen, die mir alle aktuellen Benutzernamen anzeigt. Dafür hab ich zwei Funktionen erstellt. "GetLastUserNameStartDate" gibt die letzte Namensänderung einer userId zurück und "GetUserName" gibt schließlich den aktuellen Benutzernamen einer userId zurück.

CREATE FUNCTION GetLastUserNameStartDate(userId INT UNSIGNED)
RETURNS DATETIME
BEGIN
	DECLARE startDate DATETIME;
	SELECT MAX(tableUserName.startDate)
	FROM tableUserName
	WHERE tableUserName.userId = userId
	INTO startDate;
	RETURN startDate;
END;

CREATE FUNCTION GetUserName (userId INT UNSIGNED)
RETURNS CHAR(48)
BEGIN
	DECLARE name CHAR(48);
	SELECT tableUserName.name
	FROM tableUserName
	WHERE tableUserName.startDate = GetLastUserNameStartDate(userId)
	AND tableUserName.userId = userId
	INTO name;
	RETURN name;
END;

CREATE VIEW viewUser AS
	SELECT tableUserName.name, tableUsername.startDate, tableUserName.userId
	FROM tableUserName, tableUser
	WHERE tableUserName.userId = tableUser.id
	AND tableUserName.name = GetUserName(tableUser.id)
	AND tableUserName.startDate = GetLastUserNameStartDate(tableUser.id);

Diese Sicht sieht allerdings extrem ineffizient aus. (Zum Beispiel wird zwei mal "GetLastUserNameStartDate" mit dem gleichen Parameter aufgerufen)

Bei einer so komplexen Rechenaufgabe für so selten ändernder Werte würde ich da schon eher eine zusätzliche Tabelle erstellen mit den aktuellen Benutzernamen. Aber sowas ist ja streng verboten. 😉

Überseh ich da einen einfacheren Weg?

26.10.2011 - 21:44 Uhr

Ich weiß.

Und bei BEGIN... END steht wiederum:

Um überhaupt mehrere Anweisungen verbinden zu können, muss ein Client in der Lage sein, Strings von Anweisungen zu senden, die durch das Trennzeichen ; abgegrenzt sind. Dafür sorgt der Kommandozeilen-Client mysql mit dem Befehl delimiter.

Ein komplettes Beispiel scheint es in der Doku nicht zu geben. Sorry Coder, ich bin dir deiner Hilfe sehr dankbar, aber ich habe kein Bock mehr auf dieses Beispiel. Ich habe x viele verschiedene Versionen mit und ohne DELIMITER, mit und ohne BEGIN, mit und ohne Semikolon an entsprechenden stellen, mit und ohne transaktion an der oder der Stelle, immer meckert er.

delimiter $$
begin
START TRANSACTION;

DECLARE tempuserid INT

SET @tempuserid = ( 
  SELECT tableUser.id
      FROM tableUser 
        INNER JOIN tableUserName ON tableUserName.userId = tableUser.id
	   WHERE tableUserName.name='Benutzer 2')

INSERT INTO tableUserName (userId, name, startdate)
VALUES (tempuserid, 'Neuer Benutzername', Now());

COMMIT;
end$$
delimiter;

Fehlermeldung:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'START TRANSACTION;

DECLARE tempuserid INT

SET @tempuserid = (
SELECT tableU' at line 2

Mit Semikolon hinter der Deklaration:

delimiter $$
begin
START TRANSACTION;

DECLARE tempuserid INT;

SET @tempuserid = ( 
  SELECT tableUser.id
      FROM tableUser 
        INNER JOIN tableUserName ON tableUserName.userId = tableUser.id
	   WHERE tableUserName.name='Benutzer 2')

INSERT INTO tableUserName (userId, name, startdate)
VALUES (tempuserid, 'Neuer Benutzername', Now());

COMMIT;
end$$
delimiter;

Fehlermeldung:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'START TRANSACTION;

DECLARE tempuserid INT;

SET @tempuserid = (
SELECT table' at line 2

Ohne Transaktion:

delimiter $$
begin

DECLARE tempuserid INT;

SET @tempuserid = ( 
  SELECT tableUser.id
      FROM tableUser 
        INNER JOIN tableUserName ON tableUserName.userId = tableUser.id
	   WHERE tableUserName.name='Benutzer 2')

INSERT INTO tableUserName (userId, name, startdate)
VALUES (tempuserid, 'Neuer Benutzername', Now());

COMMIT;
end$$
delimiter;

Fehlermeldung:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE tempuserid INT;

SET @tempuserid = (
SELECT tableUser.id
FROM t' at line 3

Eine andere Variante des SELECT Befehls:

delimiter $$
begin

DECLARE tempuserid INT;

  
  SELECT tableUser.id
      FROM tableUser 
        INNER JOIN tableUserName ON tableUserName.userId = tableUser.id
	   WHERE tableUserName.name='Benutzer 2' into tempuserid

INSERT INTO tableUserName (userId, name, startdate)
VALUES (tempuserid, 'Neuer Benutzername', Now());

COMMIT;
end$$
delimiter;

Fehlermeldung:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE tempuserid INT;

SELECT tableUser.id
FROM tableUser
' at line 3

Mit START TRANSAKTION und Semikolon hinter der Deklaration:

delimiter $$
begin
START TRANSACTION;

DECLARE tempuserid INT;

SET @tempuserid = ( 
  SELECT tableUser.id
      FROM tableUser 
        INNER JOIN tableUserName ON tableUserName.userId = tableUser.id
	   WHERE tableUserName.name='Benutzer 2')

INSERT INTO tableUserName (userId, name, startdate)
VALUES (tempuserid, 'Neuer Benutzername', Now());

COMMIT;
end$$
delimiter;

Fehlermeldung:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'START TRANSACTION;

DECLARE tempuserid INT;

SET @tempuserid = (
SELECT table' at line 2

... und etliche mehr habe ich ausprobiert. 😦

26.10.2011 - 18:43 Uhr

Hallo Coder007,

ich habe mir jetzt den MySQL Workbench runtergeladen. Die erste Fehlermeldung, die ich gepostet habe ist gleich geblieben. Ich denke, dass Toms Vermutung über die Ursache des Fehlers richtig ist.

Die letzten Codes von Nuky haben folgende Fehlermeldungen:

DECLARE @userid int

SELECT @userid = ( 
  SELECT tableUser.id
      FROM tableUser 
        INNER JOIN tableUserName ON tableUserName.userId = tableUser.id
	   WHERE tableUserName.name='Benutzer 2'))

INSERT INTO tableUserName (userId, name, startdate)
VALUES (@userid, 'Neuer Benutzername', Now());

Fehlermeldung:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE' at line 1

START TRANSACTION;

DECLARE tempuserid INT

SET @tempuserid = ( 
  SELECT tableUser.id
      FROM tableUser 
        INNER JOIN tableUserName ON tableUserName.userId = tableUser.id
	   WHERE tableUserName.name='Benutzer 2'))

INSERT INTO tableUserName (userId, name, startdate)
VALUES (tempuserid, 'Neuer Benutzername', Now());

COMMIT;

Fehlermeldung:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE' at line 1

Auch Variationen mit DELIMITER und sonstigem habe ich ausprobiert, irgendwo meckert er immer. 😦

Da der oben genannte INSERT INTO ... SELECT Befehl erstmal funktioniert reicht mir das erstmal. Aber eine genauere Fehlerbeschreibung ist mit diesem Tool möglich. Ich beschäftige mich jetzt aber erstmal mit Funktionen und Prozeduren.

Nochmals danke an alle für die Hilfe.

25.10.2011 - 19:41 Uhr

Kommt das über den .NET Connector? Hört sich für mich nämlich so an. Ich kann die Syntax von MySql jetzt nicht auswendig und hab kein MySql zur Hand, aber das findest du natürlich am besten raus, indem du zuerst direkt in der MySql Konsole ausprobierst, was du machen willst, bevor du das über dein C# Programm abschickst. Da solltest du dann hoffentlich sinnvollere Fehlermeldungen bekommen.

Hmm, es gibt zwar eine Eingabeaufforderung... aber ohne einen funktionierenden Strg+V Befehl ist sowas heute denke ich nicht mehr zumutbar. Ein Programm auf Windows Ebene mit einer genaueren Fehlerbeschreibung habe ich leider nicht gefunden.

Zuzeit habe ich eine C# Website, die den Code auf Knopfdruck aus einer Textdatei ausliest und eine Exception oder eine Erfolgreich-Meldung sowie ein paar Tabellen ausgibt.

Ich mache derzeit einen Crashkurs und spiel einfach mit ein paar Befehlen rum um zu gucken was funktioniert und was nicht. Wenn ich mich nicht irre, würde diese Befehlsfolge bei einer ORACLE Datenbank funktionieren.

Eventuell funktioniert auch

insert into Table(col1, col2, col3)  
select otherColumn1, 'value2', 3 from OtherTable where otherId = 42  

...zumindest lässt MSSQL sowas zu (anstatt der Projektion als ein Wert im Insert benutzt du das komplette Ergebnis eines Select als Zeile; mit Spalten und fixen Werten gemischt)

Hallo BhaaL,

der Code funktioniert auch in MySql. Ich habe ihn nochmal etwas verändert und auf das aktuelle Problem angepasst und es klappt!

INSERT INTO tableUserName(userId, name, startDate)
SELECT tableUserName.id, 'Neuer Benutzer', Now()
FROM tableUserName
WHERE tableUserName.name = 'Benutzer 2'

Da hätt ich aber auch mal selbst drauf kommen können... 😉

Nochmals danke an Euch!

24.10.2011 - 19:19 Uhr

Hallo an alle!

Das sagt die MySQL-Doku dazu:


>


>

Ergo sollte folgendes funktionieren:

  
START TRANSACTION;  
  
DECLARE userid INT  
  
SET @userid = (   
  SELECT tableUser.id  
      FROM tableUser   
        INNER JOIN tableUserName ON tableUserName.userId = tableUser.id  
     WHERE tableUserName.name='Benutzer 2'))  
  
INSERT INTO tableUserName (userId, name, startdate)  
VALUES (userid, 'Neuer Benutzername', Now());  
  
COMMIT;  
  

Das herauszufinden hat mich keine 5min gekostet. Das hättest du auch geschafft 😉

Erstmal danke, dass du das für mich gegooglelt hast. 😉

Aber der Code verursacht einen Absturz.

Fehlermeldung:
Fatal error encountered during command execution.

Auch wenn ich ihn modifiziere, zum Beispiel den "SET @userid =" Befehl rausnehme kommt eine Fehlermeldung wegen der Syntax.

Entweder ist die Doku von mySQL grottenschlecht, oder ich / wir haben nicht verstanden wie sie anzuwenden ist.

Nur mal so nebenbei, wenn du ja so oder so eine Art Login hast, wo du dir Benutzerdaten merkst...sollte dir die UserId nicht schon bekannt sein, wenn du das Insert durchführen willst?

Da hast du vermutlich recht. Ich mache derzeit einen Crashkurs und spiel einfach mit ein paar Befehlen rum um zu gucken was funktioniert und was nicht. Wenn ich mich nicht irre, würde diese Befehlsfolge bei einer ORACLE Datenbank funktionieren.

Nur nochmal zur Erklärung der Fehlerursache:
Im INSERT-Statement wird dieselbe Tabelle verwendet, wie im INNER JOIN des SELECT-Statements. Dadurch entsteht eine zyklische Abhängigkeit zwischen den beinen Einzelstatements, welche zum Abbruch führen. Vermutlich tritt der Fehler beim Versuch auf, die Anfrage intern zu optimieren und/oder die zu verarbeitenden Werte voraussagen zu können.

Danke für den Hinweis, Tom!

@ all:

Ich habe mir heute 2 Bücher über MySQL ausgeliehen. Damit werd ich mir bestimmt einen besseren Überblick über die MySQL Datenbank verschaffen.

Vielen Dank an alle und noch nen schönen Abend!!!

23.10.2011 - 18:04 Uhr

Hallo Nuky,

danke für deine Antwort(en)!!!

Dein Ansatz wird sicherlich funktionieren. Leider krieg ich es selbst nach mehreren Stunden nichtmal hin eine Variable zu deklarieren. Egal ob mit, oder ohne Trigger, mit DELIMITER oder ohne, egal von welcher Seite ich einen Codeschnipsel ausprobiere. 🙁

Ich hoffe, dass mir dabei nochmal jemand helfen kann. Kann mir jemand den folgenden Code berichtigen, sodass (mit oder ohne Trigger) eine Variable deklariert wird, die ich später in einem INSERT Befehl benutzen kann?

DELIMITER |
CREATE TRIGGER trigger_name BEFORE INSERT
ON tableUserName FOR EACH ROW
BEGIN
DECLARE @test = 1; 
END;
|
DELIMITER;

Fehlermeldung:
Fatal error encountered during command execution.

Danke.

23.10.2011 - 00:28 Uhr

Hallo Nuky,

leider klappt es nicht, die Fehlermeldung ist leider die gleiche.

22.10.2011 - 23:33 Uhr

Hallo Nuky,

nein, das ist leider nicht das, was ich suche. Nun wird ja der bisherige Benutzername überschrieben, und genau das soll nicht passieren. Ich möchte tatsächlich den INSERT Befehl benutzen und der Parameter userId soll den Wert bekommen, der bei der SELECT Anweisung als einziger zurückgegeben wird.

Die beiden Tabellen sehen so aus:

CREATE TABLE tableUser (
	id INT NOT NULL AUTO_INCREMENT,
	password VARCHAR(24),
	PRIMARY KEY(id)
);


CREATE TABLE tableUserName (
	id INT NOT NULL AUTO_INCREMENT,
	userId INT NOT NULL,
	name CHAR(48),
	startdate DATETIME,
	PRIMARY KEY(id),
	FOREIGN KEY (userId) REFERENCES tableUser(id)
);
22.10.2011 - 22:32 Uhr

Hallo Nuky,

doch das Statement macht Sinn. Ein Benutzer kann seinen Benutzernamen ändern, alle alten Benutzername und der Zeitpunkt der Änderungen bleibt aber in der Datenbank gespeichert.

22.10.2011 - 18:02 Uhr

Hallo,

ich möchte in mySQL bei einem INSERT Befehl einen Primary Key aus einer Tabelle erhalten. Leider funktioniert das nicht so, wie ich es mir vorstelle.

Bei der INSERT ... SELECT Befehlkombination können soweit ich weiß nur alle Parameter vollständig aus Tabellen gesetzt werden. Ich möchte aber nur einen Parameter aus einer Tabelle haben, und die anderen 'selbst' übergeben.

Mit folgendem Code funktionierts leider nicht, obwohl die SELECT Anweisung den richtigen Rückgabewert hat:

INSERT INTO tableUserName (userId, name, startdate)
VALUES ((	SELECT tableUser.id
			FROM tableUser, tableUserName
			WHERE tableUser.id=userId AND name='Benutzer 2'),
		'Neuer Benutzername',
		Now());

Fehlermeldung:
You can't specify target table 'tableUserName' for update in FROM clause

Kann mir jemand helfen? Vielen Dank schonmal!

Grüße
dahaack

03.10.2011 - 16:00 Uhr

Hallo Gü,

vielen Dank dafür. Werde mir das mal anschauen.

Grüße

dahaack

03.10.2011 - 15:26 Uhr

Hallo M@TUK,

vielen Dank für deine Antwort und entschuldige bitte, dass ich noch ein paar Infos vorenthalten habe.

Das UNIQUE habe ich auch schon gefunden, ist an dieser Stelle aber nicht das was ich brauche. Wenn ein Benutzername geändert wurde, darf der alte Benutzername wieder vergeben werden.

Eine IF-Abfrage ist anscheinend nur mit dem SELECT Befehl kombinierbar.
Ablaufsteuerungsfunktionen
INSERT

Die Abfrage ist etwas länger und verschachtelt, daher braucht ihr mir natürlich nicht die komplette Abfrage vordiktieren, sondern es reicht mir vollkommen, wenn ich weiß, wie eine Abfrage bedingt stattfinden kann.

Ich könnte die Abfrage natürlich auch erstmal auf dem übergeordneten Anwendungsprogramm stattfinden lassen, allerdings könnte dann der sehr unwahrscheinliche Fall eintreten, dass zwei Leute gleichzeitig einen neuen Benutzernamen mit gleichem Benutzernamen anlegen.

03.10.2011 - 14:54 Uhr

verwendetes Datenbanksystem: mySQL

Hallo,

in meiner Datenbank soll der Benutzer seinen Benutzernamen ändern können. Allerdings soll der Benutzername dabei nicht einfach überschrieben werden, sondern alle vorherigen Benutzernamen und der Zeitpunkt der Änderungen gespeichert werden.

CREATE TABLE tableUser (
	id INT NOT NULL AUTO_INCREMENT,
	password VARCHAR(24),
	PRIMARY KEY(id)
);


CREATE TABLE tableUserName (
	id INT NOT NULL AUTO_INCREMENT,
	userId INT NOT NULL,
	name CHAR(48),
	startdate DATETIME,
	PRIMARY KEY(id),
	FOREIGN KEY (userId) REFERENCES tableUser(id)
);

In der Benutzertabelle wird also nur das Passwort abgespeichert, in der Benutzernamentabelle wird der Name und der Zeitpunkt, wann dieser Name erstellt wurde abgespeichert.

Wenn also ein neuer Benutzer erstellt (oder ein Benutzername gewechselt) wird, ist das ganze nur erlaubt, wenn kein Benutzer den neuen Namen zur Zeit verwendet. Über ein bedingtes Einfügen hab ich im Netzt nicht so wirklich was gefunden. Wie kann man das realisieren (gerne auch für ein anderes Datenbanksystem, das mySQL-Äquivalente sollte ich dabei rausfinden können).

Vielen Dank schonmal!

19.09.2011 - 18:06 Uhr

Hallo chillic,

auf einem Rechner ist sowas wie Facebook sicherlich nicht möglich. Ich bin gerade dabei die MySQL Datenbank runterzuladen und ich werde beide Konzepte mal parallel programmieren und vergleichen. Wenn ich etwas interessantes herausfinde oder Hilfe brauche werd ich mich melden.

Vielen Dank an alle soweit!

dahaack

18.09.2011 - 19:49 Uhr

Auch Datenbanken sind viel komplexer, als es auf den ersten Blick erscheint 😉 Du wirst niemals in der Lage sein, von der Performance her (und allem anderen auch) an eine große Datenbank heranzukommen, die große Datenmengen verwalten muss. Zum einen ist sehr wohl möglich (und wird auch so gemacht), einen Index über die beiden ID Spalten zu erstellen. Außerdem macht eine Datenbank noch viel mehr, um die Performance zu steigern. Da gibt es allein intelligentes und ausgefeiltes und bis ins Detail konfigurierbares Cachemanagement. Es werden Statistiken geführt, es gibt einen Query Optimizer, der anhand der Statistiken optimale Zugriffspfade erstellen kann, man kann Datenbanken Clustern, man kann Dateizugriffe automatisch verteilen, wenn du sagen wir tausend Festplatten hast usw... Eine größere Datenbank wie Oracle oder DB2 ist unglaublich komplex und umfangreich. Das ist dann auch eine Lösung, die man praktisch beliebig skalieren kann.

Mag sein, dass du Recht hast. Ich tu mich halt wirklich schwer damit die objektorientierte Programmierung "aufzugeben" und ein riesen Datenwirrwarr zu akzeptieren. X(

In meiner Hauptklasser erstelle ich zum Beispiel eine Methode MakeFriends(User user1, User user2) die beiden Usern jeweils den anderen User als Freund hinzufügt.
Damit bearbeitest du also immer zwei Datensätze gleichzeitig. Das muss dann so passieren dass keiner zwischendrin die Datensätze ebenfalls anfassen will.

In diesem Beispiel sehe ich erstmal nicht das Problem. Selbst wenn beide neuen Freunde gleichzeitig während der MakeFriends Methode ihre Freunde anzeigen, ist es nicht weiter schlimm, dass für User1 bereits User2 als Freund eingetragen ist, für User2, allerdings noch nicht User1 eingetragen ist.

Und du bearbeitest immer das gesamte Objekt, nicht einfach nur einen Eintrag "A hat B als Freund", sondern (wenn man mal von XML-Dateien ausgeht) es wird der komplette (!!!) User geschrieben.

Nein, ich glaube nicht. Die Freundesliste ist ja glücklicherweise nur eine Liste aus Referenzen (also Pointern) auf die Freunde. Jede Person wird mit seinen Attributen nur einmalig abgespeichert.

und danach kann man direkt alle Freunde (und meinetwegen auch Freundesfreunde) anzeigen ohne irgendwo weitersuchen zu müssen.
Wie soll das mit den Freundesfreunden gehen?
Wenn B ein Freund von A ist und C ist ein Freund von B, wie kommst du dann von A auf C? Du willst dir ja wohl kaum sämtliche User als verzeigerte Objekte in irgendeinem wahnsinns riesen Rechner gleichzeitig halten?

Doch, so war der Plan. 😉 Ich sehe es als nicht ganz so schlimm an, wie sämltliche riesige verzweigte Tabellen in denen die Daten einfach "stupide" hintereinander geschrieben werden. Ich sehe die Synchronisation nach dem objektorientierten Konzept als nicht so schwierig zu realisieren an, wie beim Relationalen Datenbankkonzept. Das schöne an der Relationalen Datenbank ist natürlich, dass ich mich um die Synchronisation nicht mehr kümmern brauche.

Übrigens:
Mein ehemaliger DB-Prof hat eine etwa 30-köpfige EDV-Beratungsfirma. Er meinte, dass für eine Spezielle Suche eines Kunden angeblich fast 24 Stunden gebraucht würden. Er hat das ganze dann so gelöst, dass solche Suchen präventiv automatisch gestartet werden. Wenn jemand das Suchergebnis braucht, wird die letzte Suche ausgegeben, welche dann die Daten von vor etwa 24 Stunden beinhaltete.

Professoren reden aber auch manchmal recht viel, wenn der Tag lang ist... wenn ich mir aber das Konzept der Relationalen Datenbanken anschaue, dann finde ich das bei riesigen und verzweigten Tabellen und ganz ausgefallenen Suchanfragen über viele Tabellen garnicht mal so unrealistisch.

Nehmen wir mal an, man würde tatsächlich eine Seite haben in der kontinuierlich Daten gelesen und verändert werden, dann wird einem so eine Datenbank denk ich mal auch nicht kostenlos zur Verfügung stehen. Das wäre wiederum ein Vorteil der Serialisierten Klasse (sofern sowas damit überhaupt möglich wäre).

18.09.2011 - 14:25 Uhr

Mahlzeit,

Sorry, aber ich finde das Thema ist dermaßen umfangreich und komplex, dass es überhaupt keinen Sinn macht, so oberflächlich darüber zu diskutieren. Deine Frage ist viel zu allgemein. Wie ich sehe bist du nicht gerade ein Anfänger, was programmieren angeht. Dann wirst du auch einsehen, dass IT-Sicherheit ein ähnlich umfangreiches Thema ist und sich nicht in zwei Sätzen beantworten lässt. Du brauchst einfach eine bessere Vorstellung von dem Gesamtkonzept, dann wirst du solche Fragen auch nicht mehr stellen.

Ja, da hast du natürlich Recht. Die Themen Webserver, Datenbanken und die Sicherheit sind dermaßen komplex, dass man kaum rausfinden kann, wo man überhaupt anfangen soll. 🙁

Und ich muss sagen, dass ich dieses Prinzip im Gegensatz zur Objektorientierten Programmierung relativ unübersichtlich finde.

Das ist ja auch nichts neues. Das sind unterschiedliche Werkzeuge, und als Informatiker (oder E-Techniker) muss man wissen, wie man die zur Verfügung stehenden Werkzeuge einsetzt. In dem Zusammenhang gibt es auch viele Konzepte, wie ORM oder Objektorientierte Datenbanken. Ich will auf das Thema eigentlich nicht eingehen, aber ich kann dir versichern, dass relationale Datenbanken Sinn machen.

Okay, ich werde mir die Objektorientierten Datenbanken nochmal genauer ansehen.

... muss die komplette Tabelle nach dieser ID durchsucht werden ...
Dafür hat die Tabelle einen Index, mit dem sie die betroffenen Einträge schnell findet. Tabellen sind dazu gemacht.

Das verstehe ich nicht. In beiden Spalten (User1, User2) ist eine ID (Primärschlüssel) abgespeichert. Somit ist es ja nichteinmal vernünftig möglich die Zeilen nach ID-Nummern zu ordnen. Das heißt das eigentliche Programm auf tiefster Ebene wäre dann mehr oder weniger gezwungen jedes einzelne Tabellenelement zu durchsuchen und abzufragen, ob es gleich der gesuchten ID ist. Ich sehe da kaum Optimierungspotential. In der Objektorienterten Programmierung habe ich direkte Referenzen zu den gesuchten Freunden. Es findet nichtmal wirklich eine Suche statt.

Eine Klasse User hat das Attribut "friends" welches eine List<User> ist. Alle Freunde anzuzeigen ist hierbei natürlich denkbar einfach und vor allem auch schnell.
Die Freunde da hineinzukriegen erfordert allerdings Dateioperation. Und wehe du willst mal rausfinden, wer alles eine bestimmte Person als Freund hat. Dann durchsuchst du nämlich (je nach Community) tausende bis Millionen Dateien.

Ich sehe da gar kein Problem. In meiner Hauptklasser erstelle ich zum Beispiel eine Methode MakeFriends(User user1, User user2) die beiden Usern jeweils den anderen User als Freund hinzufügt. Wenn ich jetzt frage, "Wer hat alles Herrn Mayer als Freund?" ist es die gleiche Suche wie "Welche Freunde hat Herr Mayer?". Ich muss nur einmalig den Account von Herrn Mayer suchen (hier kann man zum Beispiel alphabetisch ordnen um den Namen möglichst schnell zu finden, und danach kann man direkt alle Freunde (und meinetwegen auch Freundesfreunde) anzeigen ohne irgendwo weitersuchen zu müssen. Mitlerweile haben einige Facebooknutzer ja bereits mehrere Hundert Freunde 😄, das heißt die UserHasFriend Tabelle hat damit bereits etwa
AnzahlBenutzer * einige Hundert / 2
Zeilen.

Bei der Tabelle UserWritesMessageToUser bekomm ichs mit der Angst, wenn ich an die Tabelle denke. 8o
Stattdessen: Attribut List<Message> TransmittedMessages und List<Message> ReceivedMessages und alle gesendeten und empfangenen Nachrichten von Herrn Mayer sind direkt abrufbar

Kann ich davon ausgehen, dass niemand mit einem Pointer meinen Arbeitsspeicher durchforstet oder die Datenbankdatei von der Platte D: runterlädt?
Der Server sollte natürlich so geschützt sein dass niemand dran kommt. Ohne diese Annahme ist jedes Websystem sinnlos.

😉 Da hast du wohl Recht.

Ein Beispiel am Sozialen Netzwerk:

Es gibt zum Beispiel eine Tabelle UserHasFriend in denen jeweils zwei User-IDs abgespeichert werden. Wenn jetzt für einen Speziellen User alle Freunde angezeigt werden sollen, muss die komplette Tabelle nach dieser ID durchsucht werden und hinter allen FreundesIDs sind dementsprechend die Freunde.

Im Vergleich dazu in der OOP:
Eine Klasse User hat das Attribut "friends" welches eine List<User> ist. Alle Freunde anzuzeigen ist hierbei natürlich denkbar einfach und vor allem auch schnell.

Du wirst hier an einer Relationalen Datenbank womöglich nicht vorbei kommen.
Mit einem entsprechenden ORM, wie dem Entity Framework, kannst Du aber Deine OOP Anforderung umsetzen und es werden auch nur die Properties geladen, die in diesem Moment benötigt werden: Lazy Loading => Last Senkung.

ADO.NET hält die Connection immer offen, sodass nur ein Reset stattfindet und man hier auch kaum Overhead hat.
Zudem sind bei Facebook natürlich enorme Optimierungen der SQL Befehle durchgeführt worden.

Ob ein Selektieren über viele Objekte mit vielen Verbindungen, Ausnahmen etc... im Speicher, oder ein Selektieren über viele Einträge in der Datenbank: ich vermute fast die Datenbank ist schneller.){gray}

Viele Stichworte die mich erstmal wieder beschäftigen werden. 😉

Vielen Dank an alle! 👍

17.09.2011 - 20:06 Uhr

Hallo,

vielen Dank für Eure Antworten!

Nimm doch gleich eine Instanz der nicht statischen Klasse, wozu dann noch kopieren?

Die Daten sollen ja prinzipiell von allen Seiten (Defualt.aspx, Login.aspx...) aus verändert oder gelesen werden können. Ich hab im Netz gefunden, dass dies mit einer statischen Klasse, oder mit einer Definition in der Masterklasse möglich sei.

Ich habs aber nicht hinbekommen, auf die Daten der MasterPage von der Global.asax zuzugreifen um die Daten im Application_Start Event einmalig zu laden.

Was für eine geheime Seite ists denn?

Da muss ich zugeben, dass dies noch nicht 100%-ig feststeht. Wenn dann eines Tages die zündende Idee kommt ist es natürlich gut, wenn man sich in dem Thema schon gut auskennt. Deshalb wollte ich das grobe Prinzip von z.B. Ebay oder einem Sozialen Netzwerk einfach mal nachprogrammieren.

Jeder der auf der Platte lesen kann, kommt an die Daten.

Das heißt die Daten wären so gesehen relativ sicher, da es ja in der Regel nicht möglich ist auf die Platte D eines Webservers und auf den Arbeitsspeicher eines Servers zuzugreifen?

Nachdem du die Daten sowieso per Programm entschlüsseln musst um sie auszugeben, kommt auch jeder der ans Programm ran kommt, genauso an die Daten ran.

Ja. Meine Hoffnung bestand natürlich auch darin, dass keiner an mein Webseitenprogramm rankommt. Ich hab leider relativ wenig Ahnung von WebServer und speziell inwieweit man als "Außenstehender" auf die Daten eines Servers zugreifen kann. Aber so wie es aussieht muss ich die Daten wohl sowieso nicht verschlüsseln.

Passwörter solltest du mit einem (salted) Hash schützen.

Jo, danke für den Hinweis! Werd mich damit mal beschäftigen.

Wenn du viele Daten hast, würd ich über eine Datenbank nachdenken. Nicht wegen dem Schutz (denn die Zugangsdaten stehen wie gesagt lesbar im Programm), sondern wegen dem Komfort beim Zugriff.

Ich (frisch gewordener E-Tech-Ing) habe ein Semester Datenbanken gehabt, in denen ich das Prinzip der Relationalen Datenbanken kennengelernt habe. Und ich muss sagen, dass ich dieses Prinzip im Gegensatz zur Objektorientierten Programmierung relativ unübersichtlich finde.

Ein Beispiel am Sozialen Netzwerk:

Es gibt zum Beispiel eine Tabelle UserHasFriend in denen jeweils zwei User-IDs abgespeichert werden. Wenn jetzt für einen Speziellen User alle Freunde angezeigt werden sollen, muss die komplette Tabelle nach dieser ID durchsucht werden und hinter allen FreundesIDs sind dementsprechend die Freunde.

Im Vergleich dazu in der OOP:
Eine Klasse User hat das Attribut "friends" welches eine List<User> ist. Alle Freunde anzuzeigen ist hierbei natürlich denkbar einfach und vor allem auch schnell.

Bedenke immer, dass der IIS bzw. Deine Anwendung viele verschiedene Threads hat, die womöglich dann zeitgleich auf Deine "Datenbank" zugreifen.

Das ist in der Tat ein Problem über das ich mir nochmal Gedanken machen muss. Danke für den Hinweis.

Hierzu gehört neben allen Zugriffen auf eine Seite auch die Resourcen, und alles was in der Global-Definition gesetzt wurde.

Ich versuche natürlich alle Daten in einem einzigen Objekt zu kapseln. In der Global.asax (falls ich dich richtig verstehe) sind bisher keine Daten definiert.

Frameworks wie Linq2Sql und EF fördern die Sicherheit durch das richtige Behandeln von SQL Befehlen.

Du meinst die Sicherheit im Bezug auf gleichzeitiges Zugreifen / Schreiben?

Ich sehe im Moment keine Verbindung zu Deiner Sicherheitsanforderung und der Datenhaltung im Speicher. Wenn jemand an die Daten will, dann kommt er ran. Ob nun physikalisch oder übers Netz kommt auf viele Faktoren an.

Okay. Die Frage ist, ob man an die Daten leichter kommt, als wenn ich eine SQL Datenbank verwende? Kann ich davon ausgehen, dass niemand mit einem Pointer meinen Arbeitsspeicher durchforstet oder die Datenbankdatei von der Platte D: runterlädt?

Vielen Dank nochmal für Eure kompetente Hilfe!

17.09.2011 - 13:01 Uhr

Hallo,

ich möchte für eine eigene Webseite eine Datenbank haben, die zum Beispiel Benutzernamen und Passwörter, später aber auch sehr "verzweigte" Objekte speichern und laden können soll.

Die für die Website benötigten Daten habe ich alle in eine statische Klasse gepackt, damit ich auf die Daten global zugreifen kann.

Die Daten werden abgespeichert, indem ich die Daten der statischen Klasse in eine nicht statische Klasse kopiere, welche die gleichen Attribute hat. Diese Klasse wird serialisiert und auf Platte D: (Ordner wird für den Admin freigegeben) abgespeichert. Beim Serverstart wird die Datei einmalig geladen und in die statische Klasse kopiert.

Meine Frage:

Wie sicher ist das ganze? Braucht man eine SQL, LINQ oder sonstwas Datenbank um die Sicherheit vor Hackern zu gewährleisten? Müssen die Daten im Arbeitsspeicher verschlüsselt werden? Müssen sie auf der Platte verschlüsselt werden? Ist das allgemeine Konzept mit der statischen und nicht statischen Klasse tragbar? 😉

Vielen Dank schonmal an Euch!

13.07.2011 - 18:05 Uhr

Hallo herbivore,

danke für die Antwort. 👍

Grüße

dahaack

12.07.2011 - 20:01 Uhr

Hallo Gü,

(nur als Stichwort: volatile)

Jo danke, wenn ich einmal mehr Threads benutze werd ich dran denken.

Das habe ich oben schon erwähnt: statt Polling (und auch mit dem Timer ist das nix anderes) verwende ein Ereignis.

Auch hier nochmal danke für deinen Tipp. Dieses Testprogramm ist so zusammengewachsen. Mit einem sauberen durchdachten Programm hat das nichts zu tun sondern ist ausschließlich zum Testen der Threads. 😉

Grüße

dahaack

12.07.2011 - 19:43 Uhr

Hallo Gü,

danke für deine Antwort.

Represents a lock that is used to manage access to a resource, allowing multiple threads for reading or exclusive access for writing.

Ich sehe da genau mein Problem: Ich habe zwei Threads, die sich bei der Variablenübergabe ein wenig abstimmen müssen.

Verwende also nur einen Monitor bzw. den Syntax-Zucker lock.

Okay, werd mir das mal anschauen, danke.

Du solltest generell die MSDN dazu lesen.

Das mache ich natürlich, wie gesagt, ich sehe in der Beschreibung genau mein Problem.

12.07.2011 - 19:19 Uhr

Hallo,

ich möchte den Lese-Zugriff auf die Daten einer Klasse mit der ReaderWriterLockSlim-Klasse sperren.

Um die Sperrung zu Testen habe ich mir ein kleines Programm geschrieben. In der MyProcessClass.ProcessMethod() findet eine lange Schleife statt, die das Attribut progress der Klasse ändert. Diese Methode wird von einem Thread aus der Methode StartProcessThread() gestartet.

Über den Button1 starte ich den Thread. Zunächst wird die lange Schleife durchlaufen, die das Attribut progress aktualisiert. Danach soll das Lesen der Attribute gesperrt werden. Nach dem Sperren wird noch einmal eine lange Schleife durchlaufen und das Attribut aktualisiert. An einem Progressbar der Windowsform (wird durch Timer aktualisert) kann ich aber erkennen, dass die Lesesperre nicht eingetreten ist. Der Progressbar läuft wie in der ersten Sperre von 0 langsam nach 100. (Über den Button2 kann ich testweise nochmal den aktuellen Progress-Wert in einem Label anzeigen lassen)

class MyProcessClass
    {
        //private Object thisLock = new Object();
        private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
        
        private int var1 = 0;
        private int var2 = 0;
        private int progress = 0;



        public MyProcessClass()
        {

        }

        public void StartProcessThread()
        {
            Thread processThread;
            processThread = new Thread(ProcessMethod);
            processThread.Start();
        }

        public void LongMethod()
        {
            for (int i = 0; i <= 100; i++)
            {
                var1 = i;
                progress = i;
                for (int j = 0; j <= 1000; j++)
                {
                    for (int k = 0; k <= 10000; k++)
                    {
                    }
                }
            }
        }

        public void ProcessMethod()
        {
            int par1 = var1;
            int par2 = var2;


            for (int i = 0; i <= 100; i++)
            {
                progress = i;
                for (int j = 0; j <= 1000; j++)
                {
                    par1++;
                    for (int k = 0; k <= 10000; k++)
                    {
                        par2++;
                    }
                }
            }

            // Wait until the ReadLock is entered
            do
            {
                cacheLock.EnterReadLock();
            }
            while (!cacheLock.IsReadLockHeld);              // <<<=== HIER SOLL DIE LESESPERRE EINTRETEN
            LongMethod();
            var1 = par1;
            var2 = par2;
            // Exit ReadLock
            cacheLock.ExitReadLock();
        }

        public int[] GetProcessVars()
        {
            int[] vars = new int[2];
            vars[0] = var1;
            vars[1] = var2;
            return vars;
        }

        /// <summary>
        /// Progress in %.
        /// </summary>
        public int Progress
        {
            get { return progress; }
            set { progress = value; }
        }
    }

    public partial class Form1 : Form
    {
        private MyProcessClass myProcess = new MyProcessClass();
        

        

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            myProcess.StartProcessThread();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            progressBar1.Value = myProcess.Progress;             // <<<=== HIER WIRD ALLE 0,1 SEKUNDEN EIN ATTRIBUT AKTUALISIERT
        }

        private void button2_Click(object sender, EventArgs e)
        {
            label1.Text = myProcess.Progress.ToString();
            label1.Text = myProcess.GetProcessVars()[0].ToString();
        }
    }

Warum funktioniert die Lesesperre nicht?

Vielen Dank schonmal im Voraus.

12.07.2011 - 18:57 Uhr

Der Thread wurde wegen einem Missverständnis geschlossen und ist nun wieder geöffnet.

Programmierhans schrieb vor einem Monat per PM an die Mods:

Ich verstehe das Problem eher so:

Er verwendet eine fremdes Dll.

Darin gibt es das InterfaceA.

Innerhalb des Dll gibt es mehrere Klassen die das Interface implementieren.

LibClassA:InterfaceA
LibClassB:InterfaceA
LibClassC:InterfaceA

Er hat nun das Problem, dass er eine zusätzliche Funktionalität braucht die dann aber in allen Ableitungen von InterfaceA (also in LibClassA/LibClassB/LibClassC) verfügbar sein soll. (dies würde erkären wieso er immer von der Instanz des Interfaces redet... eine Instanz des Interfaces kann ja nur eine Instanz einer konkreten Klasse sein welche das Interface implementiert)

Deshalb hat er eine Klasse SeineClass:InterfaceA erstellt.
z.B: über eine Factory erhält er dann eine Konkrete Instanz (LibClassA/B/C)... und muss dann natürlich aus SeineClass auf die effektive Instanz wrappen. (oder die Instanz rausstellen).

Dies jedefalls würde erklären, wiese er nicht direkt von der konkreten Klasse ableiten kann (also er kann nicht von LibClassA/B/C ableiten... sonst müsste er seinen neuen Code 3 mal implementieren.

Könnt Ihr den Thread nochmal aufmachen und meinen Post da reinhängen ?

Danke und Gruss
Programmierhans

So habe ich das auch gemeint. Ich habe das Problem "per Hand" gelöst. Rein aus Interesse kann der Thread - falls jemand will - ja trotzdem noch beantwortet werden, falls es eine elegantere Lösung für das Problem gibt.

Grüße

dahaack

10.06.2011 - 14:50 Uhr

Oh, dann kann ich Euch nicht ganz folgen.

Sobald ich von dem Interface ableite, müsste ich ja alle Methoden und Properties implementieren. Wenn ich also laut deiner Aussage nichts überschreiben oder weiterleiten muss, so darf ich von dem Interface also nicht ableiten.

Dein Vorlschlag ist also eine Klasse (ich nenne sie Klasse1) zu erzeugen und von dieser Klasse eine Klasse (ich nenne sie Klasse2) abzuleiten.

Wenn ich dich richtig verstehe, beihnaltet Klasse1 eine Instanz des Interface, Klasse2 beinhaltet die zusätzliche Eigenschaft.

Wenn ich nun in meinem Programm eine Instanz der Klasse2 erstelle, so kann ich auf die Methoden ja nur indirekt zugreifen, indem ich mir über ein Propertie das Interface zunächst raushole, und dann die Methoden aufrufe.

Mein Ziel wäre jedoch eine Klasse zu erstellen, die diese Methoden direkt aufrufen kann, ohne dass man sich das Interface aus der Klasse1 "rausholen" muss.

Also statt

K2Inst.InterfaceInst.Methode1();
K2Inst.Methode1();
10.06.2011 - 12:50 Uhr

Hallo herbivore,

du willst die Eigenschaft doch nicht dem Interface hinzufügen, bzw. kannst das nicht, weil das Interface von der Bibliothek vorgegeben ist.

Richtig.

Du willst die Eigenschaft der Klasse - ebenfalls aus der Bibliothek - hinzufügen, die das Interface implementiert. Sehe ich das alles richtig?

Die zusätzliche Eigenschaft hat mit der Bibliothek nichts zu tun. Dem Interface soll einfach eine bool'sche Variable hinzugefügt werden. Da ein Interface keine Variablen beinhalten kann, muss meine zu erstellende Klasse also eine "echte" Klasse sein.

Wenn ja, wäre es doch am einfachsten eine Unterklasse der Klasse zu erstellen. Die Unterklasse hätte dann die zusätzliche Eigenschaft. Sofern es sich bei der anderen Sprache auch um eine .NET-basierte handelt und die Klasse nicht sealed ist, sollte das ohne Weiteres gehen.

Genau das ist auch mein Plan. Wie gesagt, finde ich es aber nicht so schön, dass ich jede Methode und jede Propertie an die Interface-Instanz "per Hand" weiterleiten muss.

Aber solange das Endergebnis funktioniert, kann ich mich damit abfinden.

Vielen Dank nochmal.

10.06.2011 - 11:25 Uhr

Okay, vielen Dank an Euch!

Grüße

dahaack

10.06.2011 - 11:11 Uhr

Hallo dN!3L,

du hast es denke ich (fast) richtig verstanden. Der Unterschied, den ich zum Decorator erkenne ist, dass beim Decorator noch eine "Zwischenklasse" erstellt wird, den Dekorierer.

In meinem Beispiel habe ich bisher nur den KonkretenDekorierer der von dem Interface direkt erbt und eine Instanz dieses Interfaces selbst beinhaltet.

Mit elegant meine ich hier, dass ich nicht jede Methode per Hand an die Instanz innerhalb der Klasse weiterleiten möchte, sondern dass dies - wie auch immer (zum Beispiel mit nem anderen Entwurfsmuster) - automatisch passiert.

Als Ansatz fällt mir sowas wie eine überschreibende Methode ein. Das heißt eine Methode bei deren Aufruf immer die übergeordnete Methode aufgerufen wird, solange diese in der Klasse selbst nicht überschrieben wird. Soweit ich das Thema überblicke ist diese "Eleganz" wohl nicht mit meinem aktuellen Problem vereinbar.

Da ich ein Interface habe, müssen soweit ich weiß alle Methoden tatsächlich geschrieben werden, ohne an dem aktuellen Problem irgendwas "automatisieren" zu können, sehe ich das richtig?

Vielen Dank!

dahaack

10.06.2011 - 10:22 Uhr

Hallo,

ich habe eine Bibliothek aus einer anderen Programmiersprache aus der ich ein Interface benutze. Diesem Interface möchte ich eine weitere Eigenschaft hinzufügen.

Meine Idee ist folgende: Ich erstelle eine Klasse, in der eine Instanz dieses Interfaces vorhanden ist und füge der Klasse die zusätzliche Eigenschaft hinzu. Durch eine Vererbung der Klasse aus dem Interface, zwinge ich diese Klasse dazu jede Methode des Interface überschreiben zu müssen.

Nun kann ich jede zu überschreibene Methode direkt "weiterleiten" an die Instanz des Interface.

Zum Beispiel:

public IEnumerator GetEnumerator()
        {
            return interfaceInstance.GetEnumerator();
        }

Meine Frage lautet, ob dies nun sauberer Programmierstil ist, oder ob das irgendwie auch eleganter geht. Unsinnig finde ich jetzt zum Beispiel die Methoden an die Interfacemethoden "per Hand" weiterzuleiten.

Danke!

dahaack

13.05.2011 - 16:41 Uhr

Vielen Dank an Euch, es klappt jetzt.

habe Coders ersten Kommentar wohl zu schnell gelesen und aus "SelectedImageKey" "...SelectedNode.ImageKey" rausgelesen. 😃

Vielen Dank nochmal!

13.05.2011 - 16:03 Uhr

Hallo unconnected,

auch an die ein großes Danke für deine Hilfe.

Ich weiß zwar nicht woher du weißt, dass ich das Bild erst nach dem adden zugewiesen habe, aber du hast dabei Recht. 🙂

Nur löst es das Problem nicht. Ich habe jetzt die Instanz eines Knotens erstellt, weise ihm ein Bild zu und addiere ihn schließlich zu der TreeView.

Das alte Problem hat sich nicht verändert. Ich habe das MousUp-Event verwendet, da sich zu diesem Zeitpunkt das Bild ändert. Wenn ich also auf einen Knoten klicke, bleibt das richtige Bild zunächst vorhanden, auch wenn der Knoten bereits einen blauen Hintergrund hat. Erst wenn ich die Maustaste loslasse, wird der Text des Trees gestrichelt umrahmt ( = selektiert) und das Bild ändert sich.

13.05.2011 - 15:31 Uhr

Hallo Coder007,

danke für deine Antwort. Bisher hat sie mir leider nicht wirklich weitergeholfen. Per MessageBox habe ich überprüft, welchen SelectedImageKey der Knoten hat, nachdem ich diesen Key zugewiesen habe:

private void treeView1_MouseUp(object sender, MouseEventArgs e)
        {
            treeView1.SelectedNode = treeView1.GetNodeAt(new Point(e.X, e.Y));
            treeView1.SelectedNode.ImageKey = "beispielIcon.bmp";
            MessageBox.Show(treeView1.SelectedNode.SelectedImageKey);
        }

Es öffnet sich die MessageBox ohne Inhalt. Der SelectedImageKey hat also den Wert "".

EDIT: Nun habe ich mal kurz vor und nach der MessageBox per Debugger in die Knoten reingeschaut: Hier ist unter ImageKey der richtige Wert "beispielIcon.bmp" angegeben.

Das Icon existiert, da es ja bei den anderen Knoten angezeigt wird, nur bei dem jeweils selektierten wählt er immer das nullte Bild aus.

13.05.2011 - 15:12 Uhr

Guten Tag,

ich habe ein TreeView-Steuerelement, dem in jedem Knoten ein Image zugewiesen wird.

Ich habe leider das Problem, dass der selektierte Knoten immer das Image[0] anzeigt.

Habs zum Beispiel mit dem MouseUp-Event, aber auch mit einem Timer probiert. Sobald ich einen anderen Knoten selektiere, hat der ausgewählte Knoten das nullte Image und der zuvor selektierte Knoten das richtige Image.

private void treeView1_MouseUp(object sender, MouseEventArgs e)
        {
            treeView1.SelectedNode = treeView1.GetNodeAt(new Point(e.X, e.Y));
            treeView1.SelectedNode.ImageKey = "beispielIcon.bmp";
        }

Gibts denn keine Möglichkeit einem selektierten Knoten ein Image zuzuordnen? Hab bereits in den Eigenschaften des TreeView-Elementes gesucht, ob es eine Eigenschaft gibt, die es verhindert das korrekte Bild anzuzeigen, habe jedoch leider nichts gefunden.

Per MessageBox.Show(...) habe ich überprüft, ob beim MousUp-Event der richtige Knoten selektiert ist: Ja, ist er.

Ich hoffe sehr, dass mir jemand von Euch helfen kann und bedanke mich schonmal.

dahaack

19.03.2011 - 12:21 Uhr

Hallo Leutz,

ich würd gern endlich mal den Sinn von Properties verstehen. Seit längerem deklariere ich alle Variablen in allen Klassen als public, da ich mir damit den "Umweg" über die Properties erspare.

Wenn ich auf eine Variable einer Instanz zugreifen möchte und diese auf private steht, müsste ich entweder die Sicherheitsebene auf public wechseln oder die Properties hinzufügen. Aber warum nicht einfach auf public setzen?

Ich kenn ein Beispiel wo die Properties sinnvoll sind: Wenn Daten aus einer Instaz geladen werden soll, vorher jedoch noch bearbeitet werden sollen (z.B. Wenn ein Winkel in Grad abgespeichert ist, man ihn aber in Rad haben möchte). Aber ich denk mal das ist nicht Sinn und Zweck der Properties.

Vielen Dank!

24.02.2011 - 18:08 Uhr

Hallo,

nochmal vielen Dank für die Hilfe. Bin ein C# Quereinsteiger und tu mich deshalb mit einigem noch ein bisschen schwer.

Danke an Euch!

19.02.2011 - 20:14 Uhr

Hallo herbivore,

vielen Dank!

Was passiert in einer nicht überschriebenen Equals Funktion?

Die Methoden des .NET Frameworks verwenden intern in der Regel Equals und würden dann bei deiner Klasse auf die Nase fallen.

Du meinst die Klassen des .NET Frameworks? Entweder versteh ich die Antwort nicht oder sie beantwortet meine Frage nicht. 😉

Meine Frage war, wie die interne virtuelle Equalsmethode der Klasse System.Object implementiert ist, ob diese einfach nur die Adresse der beiden Objekte vergleicht?

Naja, eben ob es sich auf Ebene des Konzept - also bevor es um die Implementierung geht - um einen Werttyp handelt.

Hmm, tut mir leid ich versteh es noch nicht. Meinst du mit:

Konzeptioneller Referenztyp: Ein Typ der bei einer Vergleichsmethode die Referenz vergleicht.
Konzeptioneller Werttyp: Ein Typ der bei einer Vergleichsmothode die Werte vergleicht.

?

19.02.2011 - 18:08 Uhr

Hallo,

vielen Dank an Euch!

Da das in der Regel für die meisten (veränderbaren) Datentypen genau das selbe ist braucht man es nicht zu überschreiben

Dies ist bei mir nicht der Fall. Ich habe 2 separate Objekte, die auf Wertgleichheit überprüft werden sollen.

Beim Equals hingegen werden normalerweise die einzelnen Properties gegeneinander abgeprüft.

Ich versteh nicht ganz, warum C# es so kompliziert gemacht hat, dass man das noch selbst überschreiben muss... Was passiert in einer nicht überschriebenen Equals Funktion?

Normalerweise wird man Typen, die konzeptuell Referenztypen sind, auch als technisch als Referenztypen (class) implementieren und Typen, die die konzeptuell Werttypen sind, auch als technisch als Werttypen (struct) implementieren

Bevor ich deine weitere Antwort verstehen kann muss ich erstmal wissen was du mit konzeptueller Wert-/Referenztyp meinst. Google findet für "&quot;konzeptueller werttyp&quot; c#" kein Suchergebnis. 😉

Vielen Dank nochmal!

18.02.2011 - 22:35 Uhr

Guten Abend,

ich möchte den == Operator zum überprüfen der Wertgleichheit von 2 Objekten prüfen.

Auf Richtlinien zum Überschreiben von Equals() und des Operators == steht:

Standardmäßig prüft der Operator == auf Verweisgleichheit, indem er ermittelt, ob zwei Verweise dasselbe Objekt angeben. Deshalb müssen Referenztypen keinen Operator == implementieren, um diese Funktionalität zu erhalten. Wenn ein Typ unveränderlich ist, d. h., wenn die in der Instanz enthaltenen Daten nicht geändert werden können, kann ein Überladen des Operators == zum Prüfen der Wertgleichheit statt der Verweisgleichheit nützlich sein. Der Grund dafür ist, dass bei unveränderlichen Objekten davon ausgegangen werden kann, dass sie identisch sind, wenn sie identische Werte haben. Es wird davon abgeraten, den Operator == in nicht unveränderlichen Typen zu überschreiben.

Ich versteh es nicht. Warum wird davon abgeraten? Ich möchte den == Operator überschreiben weil == einfacher zu lesen ist als *.Equals(...).

Ich bedanke mich schonmal!