EDIT 1 : Ça marche mais j'ai encore quelques problèmes par rapport à l'EF en général (voir questions en bas de ce message)
----------
Bonjour!
Je suis assez déçu par Linq & Entities Framework... oui, car très récemment j'ai commencé un projet, basé sur moins d'une dizaine de tables avec des contraintes bien définies dans la base de données, bref une bonne base.
J'ai fait plusieurs tests avec et comme ceux ci s'avéraient être des succès j'ai décidé de l'utiliser vraiment dans mon projet en faisant tout avec l'Entities Framework (ou plutôt disons toute la partie simple des requêtes, certaines requêtes ont été laissées en SQL pour plus de facilité et de lisibilité car les LEFT JOIN sont certainement plus simple à mettre en place par des ordres SQL, et plus performantes si on les écrit bien).
Tout allait bien jusqu'au moment où j'ai heurté le premier problème :
L'exception de l'objet Entities Context qui devenait instable. Une petite recherche sur internet m'a permis de comprendre qu'il valait mieux avoir un Context global pour éviter les problèmes. C'est ce que j'ai fait (même si d'un côté technique cela enlève assez le principe de transaction qui était vraiment intéressant et apporté par l'EF (entities framework)).
Et récemment, un problème incompréhensible s'est mis à s'afficher juste au pire moment car tout le transfert est déjà effectué vers ce système et impossible de revenir en arrière :
Des erreurs de contraintes d'intégrité invalides sont apparues soudainement SANS modification de la base de données.
Lorsqu'on travaille avec des bases de données de plus de 10 000 entrées et sur un projet qui est utilisé quotidiennement, j'avoue que je n'ai pas apprécié ce "coup bas" soudain (car cela fonctionnait très bien avant).
Après plusieurs recherches sur internet, toujours rien... frustration totale, à chaque ajout de nouvelle entité dans le contexte, le SaveChange() envoie une exception comme quoi une contrainte d'intégrité n'est pas respectée, ce qui n'est pas le cas.
La solution? Aucune en Entities Framework jusqu'à maintenant... personne ne semble avoir ce problème...
Les réponses que j'ai eu jusqu'à présent sont des questions par rapport à la validité de mon ajout dans le contexte ou des relations d'intégrité invalides, malheureusement ce sont des questions que je me suis déjà posé et la réponse est toujours que la base de données est intacte et fonctionnelle.
Donc, j'ai du à chaque .AddTo<nomdel'entité>(<instance de l'entité>) me faire une requête SQL similaire.
Bien entendu cela fonctionne parfaitement car comme je l'ai dit la base de données elle même ne pose aucun problème, mais j'ai donc du code "sale" : la moitié en Entities Framework, et la moitié en SQL juste au moment des ajouts.
Il est à noter que les modifications sur les entités déjà présentes ne semblent pas poser de problème lors de l'appel de SaveChange, ce sont simplement les ajouts de nouvelles entités dans le contexte qui posent problème.
Assez parlé de ma frustration, passons au code pour vous montrer le problème (au cas où quelqu'un trouverait la solution) :
Le meilleur des exemples est :
Ce code échouera. Il n'y a aucun lien NON NULL qui pointe vers une autre table comme le définit le script de la table ci dessous (et vérifié plusieurs fois par d'autres méthodes) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
27
28
29
30
31
32
33
34
35
36
37 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using palarcdbModel; public partial class AS_Default2 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { WSUser x = new WSUser(); x.Email = "myemaill@myprovider.com"; x.Language = "en"; GB.Context.AddToWSUsers(x); GB.Context.SaveChanges(); } }
Pour finir, voici l'erreur qui est affichée :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 CREATE TABLE [palarcdbu].[WSUser]( [IDUser] [int] IDENTITY(1,1) NOT NULL, [Email] [nvarchar](150) NOT NULL, [Language] [nvarchar](2) NOT NULL, [DtCreation] [datetime] NOT NULL, [FlushNextTime] [bit] NOT NULL, [IP] [nvarchar](255) NOT NULL, [Password] [nvarchar](20) NOT NULL, [SecureMD5] [nvarchar](50) NULL, [Referer] [nvarchar](50) NULL, [LastVersion] [nvarchar](10) NULL, [LastDtActivity] [datetime] NULL, [NbActivation] [int] NOT NULL, [NbNewsletter] [int] NOT NULL, [TempValue] [bit] NOT NULL, [DoNotSend] [bit] NOT NULL, [IDLanguage] [int] NULL, CONSTRAINT [PK_tblWSUser] PRIMARY KEY CLUSTERED ( [IDUser] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO ALTER TABLE [palarcdbu].[WSUser] WITH CHECK ADD CONSTRAINT [FK_WSUser_Language] FOREIGN KEY([IDLanguage]) REFERENCES [palarcdbu].[Language] ([IDLanguage]) GO ALTER TABLE [palarcdbu].[WSUser] CHECK CONSTRAINT [FK_WSUser_Language] GO ALTER TABLE [palarcdbu].[WSUser] ADD CONSTRAINT [DF_tblWSUser_FlushNextTime] DEFAULT ((1)) FOR [FlushNextTime] GO ALTER TABLE [palarcdbu].[WSUser] ADD CONSTRAINT [DF_Table1_NbDownloads] DEFAULT ((0)) FOR [NbActivation] GO ALTER TABLE [palarcdbu].[WSUser] ADD CONSTRAINT [DF_tblWSUser_NbNewsletters] DEFAULT ((0)) FOR [NbNewsletter] GO ALTER TABLE [palarcdbu].[WSUser] ADD CONSTRAINT [DF_tblWSUser_TempValue] DEFAULT ((0)) FOR [TempValue] GO ALTER TABLE [palarcdbu].[WSUser] ADD CONSTRAINT [DF_Table1_NoCommunication] DEFAULT ((0)) FOR [DoNotSend] GO
Pourquoi l'Entities framework décide que les contraintes ne sont pas respectées sur un objet sur lequel je ne travaille pas? Aucune idée!Server Error in '/palarc' Application.<br/>
Entities in 'Entities.WSUser_Detail' participate in the 'FK_WSUser_Detail_WSCountry' relationship. 0 related 'WSCountry' were found. 1 'WSCountry' is expected.
That happens when it's on the line 17 :
Line 17: GB.Context.SaveChanges();
The stacktrace is :
[UpdateException: Entities in 'Entities.WSUser_Detail' participate in the 'FK_WSUser_Detail_WSCountry' relationship. 0 related 'WSCountry' were found. 1 'WSCountry' is expected.]
System.Data.Mapping.Update.Internal.RelationshipConstraintValidator.ValidateConstraints() +424
System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands() +59
System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter) +210
System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache) +117
System.Data.Objects.ObjectContext.SaveChanges(Boolean acceptChangesDuringSave) +453
System.Data.Objects.ObjectContext.SaveChanges() +9
AS_Default2.Page_Load(Object sender, EventArgs e) in c:\Programmation\Sites web\palarc\AS\Default2.aspx.cs:17
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
System.Web.UI.Control.OnLoad(EventArgs e) +99
System.Web.UI.Control.LoadRecursive() +50
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627
WSUser_Detail est une autre table de ma base de données, je ne travaille pas dessus dans la page aspx (_Default2) mentionnée ci-haut, cette erreur ne devrait donc pas apparaitre.[UpdateException: Entities in 'Entities.WSUser_Detail' participate in the 'FK_WSUser_Detail_WSCountry' relationship. 0 related 'WSCountry' were found. 1 'WSCountry' is expected.]
Je viens d'avoir un déclic, cela pourrait être relié à une autre entitée ajoutée au contexte mais qui était invalide (car j'ai effectivement eu un problème de par rapport à la FK sur WSCountry lors d'un ajout de WSUser_Detail).
Mais le pool a été arrêté et relancé plusieurs fois, aucune trace de l'Entity Context instable ne devrait être restée sur le serveur!
Y-a t'il une sauvegarde "réelle" du contexte gardée sur le serveur en tout temps même lors du stoppage de l'application web sur le serveur IIS? Là est la question!
Je continue mes tests au cas où c'est effectivement ça... si quelqu'un peut m'éclairer au niveau du stockage des données du Context par l'Entity Framework cela serait vraiment apprécié.
À bientôt et merci d'avance!
EDIT 1 :
Le problème original a été trouvé, un objet (entité) invalide (car incomplet) avait été ajouté dans le context mais je ne l'avais pas compris car c'était une erreur qui datait de plusieurs heures... et ensuite chacun de mes SaveChanges() sur d'autres tables échouaient car le contexte avait bien ajouté ET gardé en mémoire l'ajout d'entité invalide (ce qui est assez étrange car peu pratique mais bon... ça fonctionne comme ça apparemment!)
Mes problèmes actuels sont :
- Mon objet étant créé momentanément, après l'erreur il m'est impossible de rectifier cet enregistrement car il est invalide ET ajouté dans la liste des WSUser, comment faire pour supprimer les enregistrements invalides?
- Comment faire pour "résoudre" un contexte qui a un état invalide? Exemple GB.Context.CheckAndCancelBadObjects() (bon ok je rêve un peu mais vous voyez le principe?)
Partager