locked
Insertion multiple dans SqlCE sous WP7 RRS feed

  • 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,  


    Aurel BERA, Microsoft
    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    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

  • 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
  • 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,


    Aurel BERA, Microsoft
    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    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 base

    using (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
  •  

    C'est un nouveau détail important.

    Vérifiez dans le designer les types de liaison.

    Si je comprends bien votre modelé ele  vous devez avoir un lien de type many to many entre un ResourceList et ResourceModel.

    Cordialement,


    Aurel BERA, Microsoft
    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.


    • 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
  • 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