Meilleur auteur de réponses
Insertion multiple dans SqlCE sous WP7

Question
-
Bonjour à tous !
Utilisant une base de données locale SqlCE dans mon application WP7, je n'ai eu jusqu'à présent aucun soucis. Jusqu'à ce que j'ajoute une nouvelle classe modèle dans ma base de données, qui elle ne veut pas se sauver correctement.
Le code ci-dessous reprend la définition de la classe de base d'une ressource dans mon application, avec l'héritage de SqlCE pour chaque type enfant.
[Table] [InheritanceMapping(Code = SupportedModules.NOMOD, Type = typeof(ResourceModel), IsDefault = true)] [InheritanceMapping(Code = SupportedModules.CLANN, Type = typeof(Annonce))] [InheritanceMapping(Code = SupportedModules.CLDSC, Type = typeof(Description))] [InheritanceMapping(Code = SupportedModules.CLDOC, Type = typeof(Document))] [InheritanceMapping(Code = SupportedModules.CLCAL, Type = typeof(Event))] [InheritanceMapping(Code = SupportedModules.CLFRM, Type = typeof(Forum))] public class ResourceModel : ModelBase
Tout se passe très bien pour tous les types, sauf le dernier, Forum, qui lorsque je l'insère dans la db, est inséré 3 fois (là où les autres sont insérés une fois, ce qui est attendu). L'insertion (quelque soit le type à insérer) se fait via la méthode suivante :
public virtual void AddResource(ResourceModel newRes, int containerId) { using (ClarolineDataContext cdc = new ClarolineDataContext(ClarolineDataContext.DBConnectionString)) { var q = cdc.Resources_Table.Where(r => r.DiscKey == newRes.DiscKey && r.ResourceList.Id == containerId && r.resourceId == newRes.resourceId ); newRes.updated = true; newRes.loaded = DateTime.Now; bool alreadyInDb = false; if (!q.Any()) { newRes.ResourceList = cdc.ResourceList_Table.First(r => r.Id == containerId); cdc.Resources_Table.InsertOnSubmit(newRes); cdc.SubmitChanges(); cdc.Refresh(RefreshMode.OverwriteCurrentValues, newRes); } else { q.Single().UpdateFrom(newRes); cdc.SubmitChanges(); newRes.Id = q.Single().Id; alreadyInDb = true; } } }
Une piste pour comprendre pourquoi j'ai un type qui réagis différemment lors de l'insertion ?
Merci d'avance :)
jeudi 18 juillet 2013 11:42
Réponses
-
J'ai résolu mon soucis. Dans ResourceModel j'override la méthode Equals, mais en vérifiant la condition suivante :
Obj.GetType().Equals(typeof(ResourceModel))
Je n'avais aucun soucis jusqu'à présent avec les autres sous-types car ils surécrivaient tous la méthode Equals, mais pas Forum. Du coup, Une instance de Forum n'était jamais égale à elle-même.
En remplaçant la condition ci-dessus par
Obj is ResourceModel
Je n'ai plus de problèmes.
@Aurel Bera : Merci énormément pour votre aide!
- Marqué comme réponse Okhoshi mardi 23 juillet 2013 08:39
mardi 23 juillet 2013 08:38
Toutes les réponses
-
Bonjour
Pouvez-vous utiliser le debugger pour vous assurer que l'enregistrement n'est pas appelée plusieurs fois?
Aussi vous pouvez ajouter une contrainte d’unicité sur un champ et voir ou l’erreur se produit.
Cordialement,
vendredi 19 juillet 2013 09:15 -
Bonjour
Le debugger montre bien que les 3 enregistrements se font lors de la même ligne de SubmitChanges. Lorsque j'ajoute une contrainte d'unicité sur une autre colonne, le 2e enregistrement provoque une SqlCeException m'informant qu'une contrainte n'est pas respectée.
Merci pour votre aide,
Cordialement
vendredi 19 juillet 2013 10:04 -
Veuillez essayer de récupérer le SQL envoyé vers la DB:
http://msdn.microsoft.com/fr-fr/library/Bb386961(v=vs.90).aspx
Cordialement,
vendredi 19 juillet 2013 10:52 -
Voici le contenu de la console lorsque le log du DataContext de l'extrait de code ci dessus est affiché:SELECT (CASE WHEN EXISTS( SELECT NULL AS [EMPTY] FROM [ResourceModel] AS [t0] INNER JOIN [ResourceList] AS [t1] ON [t1].[Id] = [t0].[_resourceListId] WHERE ([t0].[DiscKey] = @p0) AND ([t1].[Id] = @p1) AND ([t0].[resourceId] = @p2) ) THEN 1 ELSE 0 END) AS [value] -- @p0: Input Int32 (Size = 4; Prec = 0; Scale = 0) [7] -- @p1: Input Int32 (Size = 4; Prec = 0; Scale = 0) [13] -- @p2: Input Int32 (Size = 4; Prec = 0; Scale = 0) [1] -- @p3: Input Int32 (Size = 4; Prec = 0; Scale = 0) [NOMOD] -- @p4: Input Int32 (Size = 4; Prec = 0; Scale = 0) [CLANN] -- @p5: Input Int32 (Size = 4; Prec = 0; Scale = 0) [CLFRM] -- @p6: Input Int32 (Size = 4; Prec = 0; Scale = 0) [CLCAL] -- @p7: Input Int32 (Size = 4; Prec = 0; Scale = 0) [CLDOC] -- @p8: Input Int32 (Size = 4; Prec = 0; Scale = 0) [CLDSC] -- Context: SqlProvider(SqlCE) Model: AttributedMetaModel Build: System.Data.Linq, Version=7.0.0.0, Culture=neutral, PublicKeyToken=24EEC0D8C86CDA1E SELECT [t0].[_coursId], [t0].[_version], [t0].[Id], [t0].[label], [t0].[name], [t0].[loaded], [t0].[visibility], [t0].[updated], [t0].[ressourceTypeStr] FROM [ResourceList] AS [t0] WHERE [t0].[Id] = @p0 -- @p0: Input Int32 (Size = 4; Prec = 0; Scale = 0) [13] -- Context: SqlProvider(SqlCE) Model: AttributedMetaModel Build: System.Data.Linq, Version=7.0.0.0, Culture=neutral, PublicKeyToken=24EEC0D8C86CDA1E -- CURSOR BASED INSERT [ResourceModel] -- [DiscKey] <= [CLFRM] -- [_resourceListId] <= [13] -- [ForumDescription] <= [Peut être supprimé via l'administration des forums] -- [UniqueIdentifier] <= [13-1] -- [Rank] <= [1] -- [CategoryId] <= [2] -- [CategoryName] <= [Général] -- [CategoryRank] <= [1] -- [title] <= [Exemple de forum] -- [resourceId] <= [1] -- [notifiedDate] <= [01/01/1753 00:00:00] -- [seenDate] <= [01/01/1753 00:00:00] -- [date] <= [01/01/1753 00:00:00] -- [visibility] <= [True] -- [url] <= [] -- [updated] <= [True] -- [loaded] <= [19/07/2013 03:37:01] -- AUTOSYNC [Id] <= [3] -- AUTOSYNC [_version] <= [System.Byte[]] -- CURSOR BASED INSERT [ResourceModel] -- [DiscKey] <= [CLFRM] -- [_resourceListId] <= [13] -- [ForumDescription] <= [Peut être supprimé via l'administration des forums] -- [UniqueIdentifier] <= [13-1] -- [Rank] <= [1] -- [CategoryId] <= [2] -- [CategoryName] <= [Général] -- [CategoryRank] <= [1] -- [title] <= [Exemple de forum] -- [resourceId] <= [1] -- [notifiedDate] <= [01/01/1753 00:00:00] -- [seenDate] <= [01/01/1753 00:00:00] -- [date] <= [01/01/1753 00:00:00] -- [visibility] <= [True] -- [url] <= [] -- [updated] <= [True] -- [loaded] <= [19/07/2013 03:37:01] Une exception de première chance de type 'System.Data.SqlServerCe.SqlCeException' s'est produite dans Microsoft.Phone.Data.Internal.dll Une exception de première chance de type 'System.Data.SqlServerCe.SqlCeException' s'est produite dans Microsoft.Phone.Data.Internal.dll Une exception de première chance de type 'System.Data.SqlServerCe.SqlCeException' s'est produite dans System.Data.Linq.dll Une exception de première chance de type 'System.Data.SqlServerCe.SqlCeException' s'est produite dans Microsoft.Threading.Tasks.dll Une exception de première chance de type 'System.Data.SqlServerCe.SqlCeException' s'est produite dans Microsoft.Threading.Tasks.dll Une exception de première chance de type 'System.Data.SqlServerCe.SqlCeException' s'est produite dans System.Threading.Tasks.dll
Et pour le détail de la SqlCeException :
L'exception System.Data.SqlServerCe.SqlCeException n'a pas été gérée Message=Impossible d'insérer une valeur dupliquée dans un index unique. [ Table name = ResourceModel,Constraint name = i_UID ] ErrorCode=-2147467259 HResult=-2147217873 NativeError=25016 Source=SQL Server Compact ADO.NET Data Provider StackTrace: at System.Data.SqlServerCe.SqlCeDataReader.ProcessResults(Int32 hr) at System.Data.SqlServerCe.SqlCeResultSet.InternalInsert(Boolean fMoveTo, Object sender, SqlCeUpdatableRecord record) at System.Data.SqlServerCe.SqlCeResultSet.Insert(SqlCeUpdatableRecord record, DbInsertOptions options) at System.Data.Linq.ChangeDirector.StandardChangeDirector.DoResultSetInsert(TrackedObject item) at System.Data.Linq.ChangeDirector.StandardChangeDirector.Insert(TrackedObject item) at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) at System.Data.Linq.DataContext.SubmitChanges() at ClarolineApp.VM.ClarolineVM.AddResource(ResourceModel newRes, Int32 containerId) at ClarolineApp.VM.ClarolineVM.<GetResourcesForThisListAsync>d__36.MoveNext() at System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() at Microsoft.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClassa.<OnCompletedInternal>b__1(Object state) at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark) at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark) at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) at System.Delegate.DynamicInvokeOne(Object[] args) at System.MulticastDelegate.DynamicInvokeImpl(Object[] args) at System.Delegate.DynamicInvoke(Object[] args) at System.Windows.Threading.DispatcherOperation.Invoke() at System.Windows.Threading.Dispatcher.Dispatch(DispatcherPriority priority) at System.Windows.Threading.Dispatcher.OnInvoke(Object context) at System.Windows.Hosting.CallbackCookie.Invoke(Object[] args) at System.Windows.Hosting.DelegateWrapper.InternalInvoke(Object[] args) at System.Windows.RuntimeHost.ManagedHost.InvokeDelegate(IntPtr pHandle, Int32 nParamCount, ScriptParam[] pParams, ScriptParam& pResult)
vendredi 19 juillet 2013 11:42 -
Je ne vois pas les requetés d'insert.
Avez-vous enlevée la contrainte d'unicité?
vendredi 19 juillet 2013 12:32 -
Comment afficher les requêtes d'insert ? Car en utilisant la procédure donnée, hormis l'extrait ci dessous, je n'ai rien d'autres concernant les inserts.
-- CURSOR BASED INSERT [ResourceModel] -- [DiscKey] <= [CLFRM] -- [_resourceListId] <= [13] -- [ForumDescription] <= [Peut être supprimé via l'administration des forums] -- [UniqueIdentifier] <= [13-1] -- [Rank] <= [1] -- [CategoryId] <= [2] -- [CategoryName] <= [Général] -- [CategoryRank] <= [1] -- [title] <= [Exemple de forum] -- [resourceId] <= [1] -- [notifiedDate] <= [01/01/1753 00:00:00] -- [seenDate] <= [01/01/1753 00:00:00] -- [date] <= [01/01/1753 00:00:00] -- [visibility] <= [True] -- [url] <= [] -- [updated] <= [True] -- [loaded] <= [19/07/2013 03:37:01] -- AUTOSYNC [Id] <= [3] -- AUTOSYNC [_version] <= [System.Byte[]]
Et la contrainte d'unicité était présente lors du test. Faut-il la retirer ?samedi 20 juillet 2013 12:58 -
Bonjour
Oui, retirez-le.
C'était justement pour un teste.
J’ai vu aussi qu’en effet la méthode c’est déclarée comme virtuelle.
Il n’y a pas une autre méthode qui la sur-écrit ?
Cordialement,
lundi 22 juillet 2013 11:03 -
Bonsoir,
Non, aucune méthode ne sur-écrit cette méthode. Après avoir supprimé la contrainte d'unicité, j'ai créé un projet de test dans la solution, avec juste ce code dans le code-behind de la page de baseusing (ClarolineDataContext cdc = new ClarolineDataContext(ClarolineDataContext.DBConnectionString)) { if (cdc.DatabaseExists()) { cdc.DeleteDatabase(); } cdc.CreateDatabase(); cdc.Log = new DebugStreamWriter(); Cours c1 = new Cours { officialCode = "UnitTest1", title = "Cours for UnitTest 1", sysCode = "UNITTEST1", officialEmail = "", titular = "John Doe" }; cdc.Cours_Table.InsertOnSubmit(c1); cdc.SubmitChanges(); ResourceList rl = new ResourceList() { label = "CLFRM", ressourceType = typeof(Forum), name = "Forum Unit Test", visibility = true, Cours = c1 }; cdc.ResourceList_Table.InsertOnSubmit(rl); cdc.SubmitChanges(); Forum f1 = new Forum() { CategoryId = 1, CategoryName = "Général", CategoryRank = 0, date = DateTime.Now, ForumDescription = "Général", Rank = 0, //content = "", resourceId = 1, title = "Forum for UnitTest1", url = "", visibility = true, seenDate = DateTime.Now, ResourceList = rl, }; cdc.Resources_Table.InsertOnSubmit(f1); cdc.SubmitChanges(); }
Edit : pour clarifier les choses, un Cours contient une liste de ResourceList et une ResourceList contient une liste de ResourceModel qui peuvent être des Forum.
J'ai le même soucis que décrit précédemment.
- Modifié Okhoshi lundi 22 juillet 2013 21:59 Détails du code
lundi 22 juillet 2013 20:33 -
- Modifié Aurel Bera mardi 23 juillet 2013 06:47 modif
mardi 23 juillet 2013 06:47 -
Etant donné qu'un ResourceModel ne peut appartenir qu'à une seule ResourceList, j'aurais plutôt dit qu'il s'agissait d'une relation one-to-many entre ResourceModel et ResourceList, non ?
Cependant, comme je n'ai le problème qu'avec la classe Forum, qui étend ResourceModel mais ne touche pas au code concernant cette relation, je ne comprends pas d'où vient mon soucis.
mardi 23 juillet 2013 07:33 -
Dans ce cas one-to many ressemble a être correct.
Mais pouvez-vous vérifier dans la BD au quelle ResourceList appartient les 3 Forums insérées ?
mardi 23 juillet 2013 07:37 -
Ils appartiennent toujours à la même resourceList.
mardi 23 juillet 2013 07:39 -
J'ai résolu mon soucis. Dans ResourceModel j'override la méthode Equals, mais en vérifiant la condition suivante :
Obj.GetType().Equals(typeof(ResourceModel))
Je n'avais aucun soucis jusqu'à présent avec les autres sous-types car ils surécrivaient tous la méthode Equals, mais pas Forum. Du coup, Une instance de Forum n'était jamais égale à elle-même.
En remplaçant la condition ci-dessus par
Obj is ResourceModel
Je n'ai plus de problèmes.
@Aurel Bera : Merci énormément pour votre aide!
- Marqué comme réponse Okhoshi mardi 23 juillet 2013 08:39
mardi 23 juillet 2013 08:38 -
Merci de votre retour.
Cordialement,
mardi 23 juillet 2013 08:50