Autor Beitrag
kingdave2nd
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 54



BeitragVerfasst: Fr 17.07.09 10:32 
Hallo zusammen,

ich befürchte ich bewege mich mal wieder auf totalem Neuland, aber ich probiers trotzdem mal:

Ich habe EntityModel meiner MySQL Datenbank mithilfe des MySQL .NET Providers über den Visual Studio Wizard erstellt. Dann habe ich mir eine kleine Klasse geschrieben die mir die Entity Connection zusammenbaut. Da ich denke, das das für den einen oder anderen ganz hilfreich sien könnte, hier mal der Code:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
    public class MdbConnectionMySql : MdbConnection
    {

        public MdbConnectionMySql(string ServerName, string DatabaseName, string UserName, string Password) 
            : base(ServerName, DatabaseName, UserName, Password)
        {
            providerName = "MySql.Data.MySqlClient";
            entityConn = new EntityConnection(this.GetEntityConnectionString());
        }

        public override string GetEntityConnectionString()
        {
            MySqlConnectionStringBuilder strBuilder = new MySqlConnectionStringBuilder();
            strBuilder.Database = DatabaseName;
            strBuilder.Server = ServerName;
            strBuilder.UserID = UserName;
            strBuilder.Password = Password;

            EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
            entityBuilder.Provider = providerName;
            entityBuilder.ProviderConnectionString = strBuilder.ToString();
            entityBuilder.Metadata = @"res://*/MdbModelSystemApplication.csdl|res://*/MdbModelSystemApplication.ssdl|res://*/MdbModelSystemApplication.msl";

            return entityBuilder.ToString();
        }
    }


Gut, das funktioniert aber alles einwandfrei, ich kann wie gewünscht Daten aus der DB lesen. Nun habe ich eine Eintität "MdbUser" die auf eine View in der Datenbank basiert. Das spannende dabei ist, das mir alle Attribute der Entität, die "NOT NULL" gekennzeichnet sind, als EntityKey im EntityModel angelegt werden (siehe untitled.GIF im Anhang).

Im gezeigten Screenshot ist dies das verschlüsselte Password des users das in der Datenbank gespeichert ist. Nun mal ganz abgesehen davon, dass das Attribut "userId" das einzige sein sollte, was meinem Verständnis nach als entityKey fungieren sollte, ergibt auch folgende Problematik:
Ich möchte in meiner DB Schicht direkt nach dem Laden des MDBUsers die Atribute "cryptPassword" und "passwordSalt" mit 'null' überschreiben, damit diese gar nicht erst an die Clientanwendung weitergegeben werden.
Ich erhalte dann als Fehlermeldung:

ausblenden Quelltext
1:
System.InvalidOperationException: The property 'cryptPassword' is part of the object's key information and cannot be modified.					


Setze ich den EntityKey für Crypt Password auf 'False' erhalte ich schon direkt im VS beim Build die folgende Meldung:

ausblenden Quelltext
1:
2:
Error  1  Error 3003: Problem in Mapping Fragment starting at line 252: All the key properties (MdbUserSet.authorizedUserId, MdbUserSet.created, MdbUserSet.createdBy, MdbUserSet.eMail, MdbUserSet.fullName, MdbUserSet.isDeleted, MdbUserSet.isSystem, MdbUserSet.loginName, MdbUserSet.modified, MdbUserSet.modifiedBy, MdbUserSet.passwordSalt, MdbUserSet.userId) of the EntitySet MdbUserSet must be mapped to all the key properties (v_system_user_select.authorizedUserId, v_system_user_select.created, v_system_user_select.createdBy, v_system_user_select.cryptPassword, v_system_user_select.eMail, v_system_user_select.fullName, v_system_user_select.isDeleted, v_system_user_select.isSystem, v_system_user_select.loginName, v_system_user_select.modified, v_system_user_select.modifiedBy, v_system_user_select.passwordSalt, v_system_user_select.userId) of table v_system_user_select.
  C:\usbstick\daveworldSVN\tooma\2009-07-15\Provider.Mdb\MdbModelSystemApplication.edmx  253  15  Provider.Mdb


Hier auch der Code mit dem ich auf die DB zugreife:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
            var usrQuery = from u in entities.MdbUserSet where u.loginName.Contains(loginname) && u.isSystem == 0 && u.isDeleted == 0 && u.isApproved == 1 select new { u };
            List<MdbUser> userList = new List<MdbUser>();

            foreach (var q in usrQuery)
            {
                q.u.cryptPassword = null;
                q.u.passwordSalt = null;
                userList.Add(q.u);
            }
            return userList.ToArray();


So, jetzt hoffe ich habe alle wesentlichen Informationen gepostet. Hoffe es hat sich neben mir schon mal jemand mit dem Thema beschäfitgt und kann mir beantworten, warum der EntityDesigner überhaupt auf die Idee kommt, die ganzen NOT NULL Felder als EntityKey Felder zu markieren.

Viele Grüsse

Dave
Einloggen, um Attachments anzusehen!
kingdave2nd Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 54



BeitragVerfasst: Fr 17.07.09 14:50 
Hi zusammen,

ein kleiner Nachtrag:

Ich habe noch mal weitergesucht und im Eintrag

www.devart.com/forum...iewtopic.php?p=46838

festgestellt, das es wohl mit dem Oracle .NET Provider ein ähnliches Thema gibt. Eignetlich beruhigend dass es noch andere Leidensgenossen gibt, andererseit hört sich das nach einem echten MS Bug an :(

gruss Dave
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Fr 17.07.09 23:04 
In dem Fall hatte die Tabelle ja keinen Primary Key, trifft das bei dir auch zu?

PS: Ein select new { u } ist relativ sinnlos, da genügt auch select u

_________________
>λ=
kingdave2nd Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 54



BeitragVerfasst: Mo 20.07.09 08:56 
Hi,

nein, bei mir trifft das nicht zu, es gibt einen Primary Key. Aber ganz egal, ob es einen gibt oder, es ist reproduzierbar, dass er alle "NOT NULL" Spalten der Tabelle auf IdentityKey = true setzt.

Ich habe am Wochenende noch ein bisschen weitergeforscht und folgendes dabei rausgefunden:

Ich habe als erstes meine MySQL DB komplett auf MSSQL (Version 2005) ugmeschrieben. Das erstaunliche Ergebniss: Auch in einem MS SQL Server Umfeld tritt das Phänomen auf. Nun habe ich erst dann daran gedacht, das ich alle Abfragen komplett auf der Basis von Views mache. Also habe ich im Designer dann doch mal endlich eine Tabelle anstelle einer View angegeben und siehe da, er setzt tatächlich nur noch auf dem richtigen Feld den IdentityKey auf true. Anbei auch ein Screenshot, links die Tabelle, rechts die View.

In meinem Fall eine richtig doofe Geschichte, da über die Views diverse Rollen und Berechtigungen für den Zugriff auf Objekte geprüft werden. Wenn es dafür jetzt keine Lösung gibt, heist das ein Redesign meiner kompletten Anwendung auf Basis eines ERM der keine Views unterstützt, oder Aufbau einer eigenen Datenbankobjektstruktur (STEINZEIT) oder Umstieg auf NHybernate. Alles keine schöne Sache, weil ewigst Aufwand. Somit verbleibe ich in der Hoffnung, das hier irgendwer eine Lösung für mein kleines Problem hat...

Viele Grüsse

Dave
Einloggen, um Attachments anzusehen!
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mo 20.07.09 10:54 
user profile iconkingdave2nd hat folgendes geschrieben Zum zitierten Posting springen:
Nun habe ich erst dann daran gedacht, das ich alle Abfragen komplett auf der Basis von Views mache.
Irgendwie aber logisch, dass die Entity dann read-only wird, oder? Schließlich kann das EF dann unmöglich die Update/Insert-Queries generieren - das wird auch bei NHibernate nicht anders sein.
Müssen denn Entities geupdated werden? Wenn ja, ist das einfach eine sehr OR/M-unfreundliche DB-Struktur, Updates wirst du dann wohl manuell über SPs erledigen müssen.
Jetzt aber zum Verstecken der zwei Properties:
Die Entity soll dann über WCF zum Client geschickt werden, nehme ich an? Dann wirst du von vielen hören, dass dort eine EF-Klasse sowieso nichts zu suchen habe. Stattdessen solltest du ein DTO benutzen, das aus nichts mehr als den benötigten Properties besteht, in dem du also insbesondere die zwei kritischen Werte weglassen kannst.

Wenn dir das zuviel Schreibaufwand ist ;) und du keine Probleme mit DAL-Klassen im Client hast, kannst du vielleicht auch einfach zwei verschiedene Entity-Klassen erstellen: Einmal mit, einmal ohne die zwei Werte. Möglicherweise lässt sich dann sogar die eine von der anderen ableiten, aber dafür kenne ich mich zu wenig mit dem EF aus.

PS: Sollte es statt einem cryptPassword nicht lieber ein hashedPassword sein ;) ?

_________________
>λ=
kingdave2nd Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 54



BeitragVerfasst: Mo 20.07.09 14:27 
Hi,

naja, eigentlich hatte ich vor, tatächlich die Updates/Deletes/Inserts über Stored Procedures zu erledigen. Und diese kann ich ja für die jeweilige Einfügeoperation im EntityModel hinterlegen.
Die Datenbank verfolgt tatächlich einen Objektrelationen Ansatz. Daten werden grundsätzlich in einer Objektentität abgelegt und über property Entitäten erweitert. Über Assoziationstabellen werden die Objekte miteinander assoziiert. Zugegebenermassen, vielleicht nicht der performanteste Ansatz, aber diese Datenbank soll zusammen mit einem Webservice bei verschiedenen Kundenprojekten zum Einsatz kommen, wo relativ wenig Daten verspeichert werden. Quasi eine Mini CMDB für arme ;-)))

Das mit den DTOs würde natürlich meine Verständnis-Lücke schliessen. Verstehe ich das richtig: Ein DTO ist eigentlich nichts weiter als ein Objekt ohne Methoden, (nur mit Eigenschaften) das in meinen DB Layer gefüllt und dann übertragen wird?
Und möchte ich ein Update des DAO durchführen, fülle ich auf Clientseite das DTO und im DB Layer muss ich irgendwie rausbekommen was hat sich im DTO geändert ?!?

Gruss Dave

PS: Ist auch ein Hash, der Name ist eher historisch gewachsen und jetzt mag ich Ihn nicht mehr ändern ;-)
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mo 20.07.09 15:19 
user profile iconkingdave2nd hat folgendes geschrieben Zum zitierten Posting springen:
Die Datenbank verfolgt tatächlich einen Objektrelationen Ansatz.
Dadurch wie gesagt O/RM-unfreundlich, aber ok :mrgreen: .
user profile iconkingdave2nd hat folgendes geschrieben Zum zitierten Posting springen:
Das mit den DTOs würde natürlich meine Verständnis-Lücke schliessen. Verstehe ich das richtig: Ein DTO ist eigentlich nichts weiter als ein Objekt ohne Methoden, (nur mit Eigenschaften) das in meinen DB Layer gefüllt und dann übertragen wird?
Und möchte ich ein Update des DAO durchführen, fülle ich auf Clientseite das DTO und im DB Layer muss ich irgendwie rausbekommen was hat sich im DTO geändert ?!?
Jupp und jupp. Wobei du beim Update ja einfach wiederum alle Properties übertragen kannst, um den Rest sollte sich die Entity kümmern.
Über DTO bin ich erst gestern gestolpert, ging ebenfalls um Client<->EF: blogs.msdn.com/brada...er-objects-dtos.aspx

Beim Grundproblem hilft dir das ja aber nicht wirklich weiter :( . Der Bug tritt wohl nur bei nicht-indizierten Views auf: blogs.msdn.com/brada...er-objects-dtos.aspx

_________________
>λ=
kingdave2nd Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 54



BeitragVerfasst: Mo 20.07.09 15:48 
Yes, das mit der OR/M unfreundlichkeit nehme ich aber mal bewusst in Kauf.

Soweit habe ich das dann aber jetzt kapiert und die Geschichte mit den DTOs sollte mir auch weiterhelfen.
Zudem merke ich mal wieder, es fehlt mir an ziemlich viel Design Erfahrung. Werde mich wohl noch ein bisschen mit Code Design Theorie beschäftigen müssen.

Vielen Dank für die Hilfe

Gruss Dave