ForcedCurrentValueWrite not setting DbValue with v4

Posts   
 
    
YvesVD
User
Posts: 177
Joined: 19-Oct-2006
# Posted on: 04-Oct-2013 12:57:35   

Hello,

I've a client/server architucture using DTO (data transport object) as exchange pattern. The server transforms the entity into DTO and the client does the opposite. The client uses ForcedCurrentValueWrite to manually recreate the entity. This has always been working but since version 4 the DbValue remains null after ForcedCurrentValueWrite. I need the DbValue on the client because I'm sending it back to the server in case of update.

I'm sending a sample class that does the transformation. Maybe I need to change the order of execution (IsNew, IsChanged, ...)

Thanks

Attachments
Filename File size Added on Approval
TagGebiedDtoToClientEntity.cs 5,859 04-Oct-2013 12:58.29 Approved
Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 04-Oct-2013 13:21:27   

There is another overload of the method which sets both properties, that you should use:

public virtual void ForcedCurrentValueWrite(
    Object value,
    Object dbValue
)

I see you already using that, which LLBLGen Pro runtime library version are you using?

YvesVD
User
Posts: 177
Joined: 19-Oct-2006
# Posted on: 04-Oct-2013 14:08:36   

I'm using version 4, very last build.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 05-Oct-2013 07:15:45   

You have to use the ForceDBValueWrite, insted of CurrentValue.

David Elizondo | LLBLGen Support Team
chand
User
Posts: 72
Joined: 05-Aug-2007
# Posted on: 30-Dec-2013 23:42:47   

Where can I find the method ForceDBValueWrite?

Entity has a readonly property. And I would like to change the db value on save routine. (The idea is clients should not be able to change this value)

in 3.5, we were using a work around via SetNewFieldValue

entity.Fields[field.FieldIndex] = new EntityField2(new FieldInfo(info.Name, info.ContainingObjectName,info.DataType, info.IsPrimaryKey,info.IsForeignKey,false,info.IsNullable, info.FieldIndex,info.MaxLength,info.Scale,info.Precision));

entity.SetNewFieldValue(field.FieldIndex, value);

in 4.0 the above hack is not working any more.

Tried the following, but these calls are no generating the db statements

entity.Fields.ForcedValueWrite(field.FieldIndex, value); entity.Fields.ForcedValueWrite(field.FieldIndex, value, value);

Is there any way to achieve this?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 31-Dec-2013 04:28:47   

If you write...

entity.Fields.ForcedValueWrite(field.FieldIndex, value, value);

...you are setting the same value on CurrentValue and DBValue. Then when you save it LLBLGen detects that it's no change (it's the same value), so it's not included in the UPDATE. Maybe you should set:

entity.Fields.ForcedValueWrite(field.FieldIndex, value, null);
David Elizondo | LLBLGen Support Team
chand
User
Posts: 72
Joined: 05-Aug-2007
# Posted on: 31-Dec-2013 05:14:39   

I tried variety of combinations but the column corresponding to read only property is not showing up in the update statement.

Following code didn't work either

// change the readonly value in db

entity.Fields[field.FieldIndex].ForcedCurrentValueWrite(value, null); entity.Fields.SetIsChanged(field.FieldIndex, true);

// save entity

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 31-Dec-2013 10:24:38   

If it's the only field that should change, you have to set the entity.IsDirty flag as well.

I truly hope code like this:

entity.Fields[field.FieldIndex] = new EntityField2(new FieldInfo(info.Name, info.ContainingObjectName,info.DataType, info.IsPrimaryKey,info.IsForeignKey,false,info.IsNullable, info.FieldIndex,info.MaxLength,info.Scale,info.Precision));

is no longer in your code base as that's no longer supported. Setting a field like that on an entity has no effect (as it shouldn't, it makes no sense). I know you didn't write it, it's just a heads up for where trouble may be caused. I truly don't know why they messed with the fields object in entities....

Frans Bouma | Lead developer LLBLGen Pro
chand
User
Posts: 72
Joined: 05-Aug-2007
# Posted on: 31-Dec-2013 12:00:09   

This is also not producing the update statement

entity.Fields[field.FieldIndex].ForcedCurrentValueWrite(value); entity.Fields.SetIsChanged(field.FieldIndex, true); entity.IsDirty = true;

Otis wrote:

is no longer in your code base as that's no longer supported. Setting a field like that on an entity has no effect (as it shouldn't, it makes no sense). I know you didn't write it, it's just a heads up for where trouble may be caused. I truly don't know why they messed with the fields object in entities....

I am using upgrades as an opportunity to clean up this kind of code. I removed quite a bit of customization with the last 3 upgrades (2.5 -> 2.6 -> 3.1 -> 3.5 ). I am sure developers at that time had their own reasons for writing that kind of code. Unfortunately it is very difficult to change some parts of the code without fearing the disruption. No one appreciates breaking 'working code' rage

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 31-Dec-2013 18:42:44   

Please try:

entity.Fields.ForcedValueWrite(field.FieldIndex, value, value);
entity.Fields.SetIsChanged(field.FieldIndex, true);
entity.IsDirty = true;

chand
User
Posts: 72
Joined: 05-Aug-2007
# Posted on: 31-Dec-2013 18:56:48   

No still not working, no change to the update statement

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 31-Dec-2013 19:18:44   

Just to eliminate any possibility, could you please try out the latest v.4.1 release.

chand
User
Posts: 72
Joined: 05-Aug-2007
# Posted on: 31-Dec-2013 20:05:47   

I am using latest 4.1.

I even tried this on sample project, a database with single table, with Id, Name and a Status (boolean column).

[Test] public void UpdateReadonlyPropertyTest() { CustomerEntity customer; using (DataAccessAdapter adapter = new DataAccessAdapter()) { customer = new CustomerEntity(1); adapter.FetchEntity(customer);

        }
        Assert.AreEqual("Test", customer.Name);
        Assert.AreEqual(false, customer.Status);

        customer.Name = "Test1";
        ChangeStatus(customer, true); 

        Assert.AreEqual("Test1", customer.Name);
       Assert.AreEqual(true, customer.Status);        // Fails here

        customer.Name = "Test";
        ChangeStatus(customer, false);

        Assert.AreEqual(false, customer.Status);

}

private static void ChangeStatus(IEntity2 customer, bool status) {

        //customer.Fields.ForcedValueWrite((int)CustomerFieldIndex.Status, status, null);
       //customer.Fields.ForcedValueWrite((int)CustomerFieldIndex.Status, status, status);

        customer.Fields.ForcedValueWrite((int)CustomerFieldIndex.Status, status);

        customer.Fields.SetIsChanged((int)CustomerFieldIndex.Status, true);
        customer.IsDirty = true;

        using (var adapter = new DataAccessAdapter())
        {
            adapter.SaveEntity(customer, true);
        }
    }

Query: UPDATE [WorkSpace].[dbo].[Customer] SET [Name]=@p1 WHERE ( [WorkSpace].[dbo].[Customer].[Id] = @p2) Parameter: @p1 : String. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "Test1". Parameter: @p2 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 1.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 01-Jan-2014 08:52:33   

Sorry, but ReadOnly fields are not valid candidates for updates/inserts (they are read-only). The best option is to set that flag to false and move on.

David Elizondo | LLBLGen Support Team
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Jan-2014 12:29:35   

The query engine checks whether a field is suitable for persistence and if a field is marked as 'readonly' it's not seen as a field for persistence and checks on it are skipped. In previous versions this was also the case but as your code simply inserted a new field object which didn't have the readonly flag set to true, it worked. With v4 this is no longer possible.

Question now is: is it possible to use authorizers / validators on the client to assure the field isn't set there? This makes the field settable on the server but not on the client.

A different approach is to make the field property internal. To do this, open the entity in the editor, go to the code gen. info tab, select the field in the combo and uncheck 'field property is public'. Then, add a read only property (only a getter) to a partial class to the entity which returns the internal property's value. Additionally, add a method to set the field's internal property. This way it won't show up on databinding, and it also allows you to set the field. Of course you have to unmark the field as readonly in the entity editor too wink

Frans Bouma | Lead developer LLBLGen Pro
chand
User
Posts: 72
Joined: 05-Aug-2007
# Posted on: 02-Jan-2014 03:38:25   

I got every thing I need for now.

However I think there is a use case for allowing (in the designer) the internal setter and public getter for a property mapped to database field.

It helps in the task based user interface scenarios. UI can use the rich entity for biding in queries but setter would be an explicit action.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 02-Jan-2014 13:01:51   

That is indeed a possibility, it is however a pain to generate such code in VB.NET hence we didn't add it till now.

Frans Bouma | Lead developer LLBLGen Pro