recursive SaveMulti() function?

Posts   
 
    
nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 04-Sep-2008 01:07:47   

i have an EntityCollection which doesn't seem to be working properly as far as the recursive save.

Each entity in the collection in turn contains an Entity collection -- like Customers and Orders. the colletion of Customers conatins customers who have collections of Orders

In my case i am iterating thru the list items in a control and setting properties according to the control states.

What i am concentrating on is the setting of the IsHidden checkbox.

When that is the only change, when I get to the SaveMulti(True) line at the end, there is "No Entities to save" in the output window on debug -- even though i see in debug mode that my collections do contain dirty entities, the ones where the IsHidden property was set to a differnet value than the initial value.

Shouldn't these dirty entities cause an Update to happen in the database?


                ' iterate to set evidences for groups if necessary
                For Each questionGroupListItem As AjaxControlToolkit.ReorderListItem In Me.ReorderList_QuestionGroups.Items
                    If Not questionGroupListItem.IsAddItem Then
                        With Me.SelectedQuestionGroupAssignments(questionGroupListItem.DataItemIndex)
                            .SortOrder = questionGroupListItem.DataItemIndex
                            If .IsNew Then
                                .EvidenceId = Me.Evidence.Id
                            End If

                        End With
                        'Dim eqga As EvidenceQuestionGroupAssignmentEntity = Me.SelectedQuestionGroupAssignments(questionGroupListItem.DataItemIndex)

                        ' and iterate thru the reorderlist of questions to assign them to the audit as well
                        'first find the control
                        Dim questionsList As AjaxControlToolkit.ReorderList = CType(FindControlRecursive(questionGroupListItem, "ReorderList_Questions"), AjaxControlToolkit.ReorderList)
                        For Each questionListItem As AjaxControlToolkit.ReorderListItem In questionsList.Items
                            If Not questionListItem.IsAddItem Then
                                'Dim eq As EvidenceQuestionEntity = eqga.EvidenceQuestion(questionListItem.DataItemIndex)
                                With Me.SelectedQuestionGroupAssignments(questionGroupListItem.DataItemIndex).EvidenceQuestion(questionListItem.DataItemIndex)
                                    ' deal with the hidden property by fincing thecheckbox in the reorderlistitem
                                    Dim cb As CheckBox = CType(Me.FindControlRecursive(questionListItem, "CheckBox_HideQuestion"), CheckBox)
                                    [b].IsHidden = cb.Checked[/b]
                                    If .IsNew Then
                                        .EvidenceId = Me.Evidence.Id
                                    End If
                                    .SortOrder = questionListItem.DataItemIndex
                                    If .Question.IsNew Then
                                        .Question.SortOrder = .SortOrder
                                    End If
                                End With
                            End If
                        Next
                    End If
                Next
                'For Each eqga As EvidenceQuestionGroupAssignmentEntity In Me.SelectedQuestionGroupAssignments
                '   eqga.Save(True)
                'Next
                Me.SelectedQuestionGroupAssignments.SaveMulti(True)
Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 04-Sep-2008 13:24:03   

When that is the only change, when I get to the SaveMulti(True) line at the end, there is "No Entities to save" in the output window on debug -- even though i see in debug mode that my collections do contain dirty entities, the ones where the IsHidden property was set to a differnet value than the initial value

In Debug do you find the IsHidden entityField's IsChanged property set to true? Also do you find the entity's "IsDirty" property set to true?

nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 04-Sep-2008 16:56:22   

here is what i have coming back in debug:

    Me.SelectedQuestionGroupAssignments(questionGroupListItem.DataItemIndex).EvidenceQuestion(questionListItem.DataItemIndex)
.Fields("IsHidden").IsChanged True Boolean
Me.SelectedQuestionGroupAssignments(questionGroupListItem.DataItemIndex).EvidenceQuestion(questionListItem.DataItemIndex)
.IsDirty True Boolean
Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 04-Sep-2008 17:16:23   

Strange.

Would you please attach a simple repro solution based on Northwind?

Thanks.

nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 04-Sep-2008 17:38:26   

sorry but i won't have time to configure a northwind solution and attempt to reproduce.

is there some other option for figuring this out?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 05-Sep-2008 07:43:01   

The thing is that we can't reproduce your issue with your code snippet (that seems to be ok as far as we can see). It must be another thing. Could you please post your relevant solution code so we can figure out what is happening? (you could post it at HelpDesk forum for private posting). Also please post your LLBLGen version and RuntimeLibraries version.

David Elizondo | LLBLGen Support Team
nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 05-Sep-2008 07:54:38   

i have an idea what it might be.....

obviously you can see there is a hierarchical relationship (EvidenceQuestionGroupAssignmentEntity contains an EvidenceQuestionCollection ina propertyEvidenceQuestion).

However.... i neglected to mention that this EvidenceQuestion collection is NOT part of the generated code but is in my BLL partial class. this is because i want to return a filtered EvidenceQuestionCollection as a public property of the EvidenceQuestionGroupAssignmentEntity.

That is to say, I have a partial class definition for EvidenceQuestionGroupAssignmentEntity which defines a public property EvidenceQuestion (which is an EvidenceQuestionCollection).

Her is the code for that:

Namespace VSurvey.DAL.EntityClasses

    Partial Public Class EvidenceQuestionGroupAssignmentEntity
#Region "Properties"
        Private evQuestions As EvidenceQuestionCollection
        ''' <summary>
        ''' EvidenceQuestion for the questions from the related group
        ''' </summary>
        ''' <value></value>
        ''' <returns>EvidenceQuestionCollection</returns>
        ''' <remarks></remarks>
        Public Property EvidenceQuestion() As EvidenceQuestionCollection
            Get
                If evQuestions Is Nothing Then
                    evQuestions = New EvidenceQuestionCollection()
                    Dim relations As IRelationCollection = New RelationCollection()
                    relations.Add(EvidenceQuestionEntity.Relations.EvidenceEntityUsingEvidenceId)
                    relations.Add(EvidenceQuestionEntity.Relations.QuestionEntityUsingQuestionId)
                    relations.Add(QuestionEntity.Relations.QuestionGroupEntityUsingQuestionGroupId)

                    Dim filter As New PredicateExpression(QuestionFields.QuestionGroupId = Me.QuestionGroupId)
                    filter.Add(New PredicateExpression(EvidenceFields.Id = Me.EvidenceId))
                    filter.Add(New PredicateExpression(EvidenceQuestionFields.Deleted = 0))
                    filter.Add(New PredicateExpression(QuestionFields.Deleted = False))
                    Dim sorter As New SortExpression(New SortClause(EvidenceQuestionFields.SortOrder, SortOperator.Ascending))
                    evQuestions.GetMulti(filter, 0, sorter, relations)
                End If

                Return evQuestions
            End Get
            Set(ByVal value As EvidenceQuestionCollection)
                evQuestions = value
            End Set
        End Property
#End Region

#Region "Overriden Methods"
        Protected Overrides Sub OnGetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext)
            info.AddValue("evQuestions", evQuestions)


            MyBase.OnGetObjectData(info, context)
        End Sub
        Protected Overrides Sub OnDeserialized(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext)


            Dim type As System.Type = System.Type.GetType("System.Object")
            evQuestions = CType(info.GetValue("evQuestions", type), EvidenceQuestionCollection)
            MyBase.OnDeserialized(info, context)
        End Sub
#End Region

    End Class
End Namespace

Therefore i am not sure that the presence of dirty entities in that collection "register" in the save as entities to be updated.

Is ther a way to add this new property to the list of properties the EvidenceQuestionAssignmentEntity checks for IsDirty etc when performing EvidenceQuestionAssignmentEntity.Save(True) method?

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 05-Sep-2008 09:36:44   

obviously you can see there is a hierarchical relationship (EvidenceQuestionGroupAssignmentEntity contains an EvidenceQuestionCollection ina propertyEvidenceQuestion).

However.... i neglected to mention that this EvidenceQuestion collection is NOT part of the generated code but is in my BLL partial class.

This makes sense now.

Is ther a way to add this new property to the list of properties the EvidenceQuestionAssignmentEntity checks for IsDirty etc when performing EvidenceQuestionAssignmentEntity.Save(True) method?

If there is no physical relation in the database between these 2 entities, you might have created a custom relation in LLBLGen Pro Designer, this will provide you with the appropriate plumbings.

Otherwise I think you'd better not call SaveMulti(), and instead call some Save method of your own, in which you loop on each EvidenceQuestionGroupAssignmentEntity and save its EvidenceQuestion (collection) property then call Save for the EvidenceQuestionGroupAssignmentEntity.

Anyway that's what SaveMulti() does, it actually calls Save for each entity in the collection.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39865
Joined: 17-Aug-2003
# Posted on: 05-Sep-2008 15:12:04   

What's the version of llblgen pro you're using and the runtimelib build? (see david's post above) ?

Also, don't do the FK=PK syncs yourself, that's not necessary, in fact you can de-reference entities you're working with, which I think will cause the problem.

  • Simply set properties and do a recursive save. Do NOT set FK fields to the PK value in your 'If .IsNew... ' clause, you should remove that code. It's done for you
  • Make sure you haven't hidden in the designer an m:1 relation in your entities which take part in this code.
Frans Bouma | Lead developer LLBLGen Pro
nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 05-Sep-2008 16:50:33   

Also, don't do the FK=PK syncs yourself, that's not necessary, in fact you can de-reference entities you're working with, which I think will cause the problem.

  • Simply set properties and do a recursive save. Do NOT set FK fields to the PK value in your 'If .IsNew... ' clause, you should remove that code. It's done for you
  • Make sure you haven't hidden in the designer an m:1 relation in your entities which take part in this code.

ummm, do you mean you think thiks will help solve the problem? that first sentence dosn't make sense to me with the word "cause"!

for you last point i am also unclear. do you mean: make sure ther is not a property with the same name in the generated portion of the code (evidenceQuestionGroupAssignementEntity.EvidenceQuestion) whic would "hide" the property i added in the partial class definition?

the generator version is v2.5.

runtime libraries are 2.5.7.822

nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 05-Sep-2008 17:12:34   

Walaa wrote:

If there is no physical relation in the database between these 2 entities, you might have created a custom relation in LLBLGen Pro Designer, this will provide you with the appropriate plumbings.

i'm not sure how i would do that, there is no FK relationship between EvidenceQuestionGroupAssignment and EvidenceQuestion.

the relationship from PK to FK is

EvidenceQuestion (FK) -> (PK) Question (FK) -> (PK) QuestionGroup (PK) -> (FK) EvidenceQuestionGroupAssignment.

That is to say (in english), a evidence-questiongroup assignement is associated with a question group. That question group has questions. and those questions have assignements to evidence (EvidenceQuestion).

The purpose of evidenceQuestionGroupAssignmentEntity.EvidenceQuestion is to answer the question "what evidence question assignments correspond to the EvidenceQuestionGroupAssignment?"

i can post the project file in a private thread if you like.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39865
Joined: 17-Aug-2003
# Posted on: 05-Sep-2008 18:12:21   

nilsey wrote:

Also, don't do the FK=PK syncs yourself, that's not necessary, in fact you can de-reference entities you're working with, which I think will cause the problem.

  • Simply set properties and do a recursive save. Do NOT set FK fields to the PK value in your 'If .IsNew... ' clause, you should remove that code. It's done for you
  • Make sure you haven't hidden in the designer an m:1 relation in your entities which take part in this code.

ummm, do you mean you think thiks will help solve the problem? that first sentence dosn't make sense to me with the word "cause"!


                                    If .IsNew Then
                                        .EvidenceId = Me.Evidence.Id
                                    End If

don't do that as it might de-reference the related entity. You also shouldn't do recursive saves yourselves, that's all been taken care of. - build the graph of entities - set properties - save one entity in the graph recursively.

for you last point i am also unclear. do you mean: make sure ther is not a property with the same name in the generated portion of the code (evidenceQuestionGroupAssignementEntity.EvidenceQuestion) whic would "hide" the property i added in the partial class definition?

No, I meant: don't HIDE a relation in the designer. You can hide relations in the designer, which means they don't exist. This could cause that the graph isn't traversed properly.

Anyway, after you've set the IsHidden property in code, is the entity 'dirty' ? (The IsDirty flag, is that set?)

Frans Bouma | Lead developer LLBLGen Pro
nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 05-Sep-2008 18:19:41   

Otis wrote:

No, I meant: don't HIDE a relation in the designer. You can hide relations in the designer, which means they don't exist. This could cause that the graph isn't traversed properly.

Anyway, after you've set the IsHidden property in code, is the entity 'dirty' ? (The IsDirty flag, is that set?)

ok, I understand the HIde part -- no relation is set to be hidden in our project.

to answer yoruy question, yes the Ishidden is set to true. th eproblem seems to be that since this is a property set up in a BBLL partial class definition, the genreated code is unaware of the relation and doesn't check it for IsDirty on a recursive Save().

Th eoptions seem to be a manual iteration and save of that property, unless you all have figured out a way to add a reference to the relation either in the generated code or in the partial class definition.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39865
Joined: 17-Aug-2003
# Posted on: 05-Sep-2008 18:26:45   

nilsey wrote:

Otis wrote:

No, I meant: don't HIDE a relation in the designer. You can hide relations in the designer, which means they don't exist. This could cause that the graph isn't traversed properly.

Anyway, after you've set the IsHidden property in code, is the entity 'dirty' ? (The IsDirty flag, is that set?)

ok, I understand the HIde part -- no relation is set to be hidden in our project.

to answer yoruy question, yes the Ishidden is set to true. th eproblem seems to be that since this is a property set up in a BBLL partial class definition, the genreated code is unaware of the relation and doesn't check it for IsDirty on a recursive Save().

Erm... 'IsHidden' is a simple .NET property? Ok, but does it have a mapping to a db field? Like CompanyName in the CustomerEntity ? if not, there's nothing to save...

To which field should the IsHidden value be saved to?

Frans Bouma | Lead developer LLBLGen Pro
nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 05-Sep-2008 18:31:23   

IsHidden is a property of the EvidenceQuestion, which is a property of the EvidenceQuestionGroupAssignementEntity -- but that property is NOT set up in the designer but rather in the partial class i have posted above.

so therefore the genreated code does not consider EvidenceQuestion to be part of the graph. even when it contains dirty entities, it is not save when you call EvidenceQuestionGroupAssignementEntity's Save(True) method.

nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 05-Sep-2008 18:34:53   

if you don't already, i would suggest creating an AddToGraph(EntityType) method to the base class which could be used overridden in partial classes to add custom porpertys to the recursive save.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39865
Joined: 17-Aug-2003
# Posted on: 05-Sep-2008 20:43:35   

nilsey wrote:

IsHidden is a property of the EvidenceQuestion, which is a property of the EvidenceQuestionGroupAssignementEntity -- but that property is NOT set up in the designer but rather in the partial class i have posted above.

so therefore the genreated code does not consider EvidenceQuestion to be part of the graph. even when it contains dirty entities, it is not save when you call EvidenceQuestionGroupAssignementEntity's Save(True) method.

If there's no mapping to a db field, the field won't make the entity 'dirty' as there are no fields in the entity which should be saved to the db (as no mapped field is changed).

That's why there are no dirty entities saved, as for the framework there are no dirty entities.

but I've to say I'm confused what the exact model is that you're using, as changing entity fields (through properties) and saving them works as expected.

'AddToGraph' is not necessary -> myOrder.Customer = myCustomer;

this adds myCustomer to the graph.

Frans Bouma | Lead developer LLBLGen Pro
nilsey
User
Posts: 54
Joined: 11-Jan-2008
# Posted on: 05-Sep-2008 21:16:00   

Otis wrote:

'AddToGraph' is not necessary -> myOrder.Customer = myCustomer;

this adds myCustomer to the graph.

i think you are misunderstanding the situation here....

i am talking about a special property set up separately in a partial class definiton (see the code i posted above).

think of it in terms of

myOrder.MyFavoriteCustomers.Add( new Customer() )

MyFavoriteCustomers is NOT a relationship set up in the designer but a special filtered list of customers i have created in the business logic layer in a partial class definition of OrderEntity.

Since it's not set up in the designer, it's not being checked as a dirty collection when i call myOrder.Save()

Hence the idea to create some kind of AddToGraph method. this wiuld be called in the partial class definition so that of OrderEntity like so:

Sub AddToGraph(entityName  as EntityProperty)
     ''' some code to add the name of the newly created property to teh list of things to check on save()
End Sub

My other option is to manually call save on myOrder.MyFavoriteCustomers.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39865
Joined: 17-Aug-2003
# Posted on: 07-Sep-2008 12:05:24   

Ah I see what you mean.

At the moment the concept of a graph with vertices with no edges isn't part of the runtime: an entity object graph in memory is a connected graph with vertices (entity objects) which are all connected (through references).

what you want, saving additionally entities in one go with another set of entities, is supported though: through a unitofwork simple_smile here, you add the entity in teh graph you want to fetch, specify a recursive save, and you also add the special list of entities you want to save as well, then commit the unitofwork, in one transaction. please check the manual for more information about the unitofwork, which I think is what you want.

Frans Bouma | Lead developer LLBLGen Pro