IsDirty flag is raised when object reference is changed even if there is no FK change in db

Posts   
 
    
hotchill avatar
hotchill
User
Posts: 180
Joined: 22-Jan-2007
# Posted on: 01-Apr-2015 13:06:37   

I am on version 4.0 Final.

Consider this code

var userEntity = GetUserEntityFromDb(userPK);
userEntity.Manager = GetUserEntityFromDb(userEntity.ManagerUserId);
Assert(!userEntity.IsDirty) // this is ok - Manager object was set from null
userEntity.Manager = GetUserEntityFromDb(userEntity.ManagerUserId);
Assert(!userEntity.IsDirty) // this fails - Manager object was set to different object, but FK is same

Is this by design?

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 02-Apr-2015 07:52:35   

Reproduced, using Northwind, on v.4.2:

var order = GetOrder(10643);
order.Customer = GetCustomer(order.CustomerId);
Debug.Assert(!order.IsDirty); // Passes.
order.Customer = GetCustomer(order.CustomerId);
Debug.Assert(!order.IsDirty); // Fails.

private OrderEntity GetOrder(int orderId)
{
    var order = new OrderEntity(orderId);
    using (var adapter = new DataAccessAdapter())
    {
        adapter.FetchEntity(order);
    }

    return order;
}
private CustomerEntity GetCustomer(string customerId)
{
    var customer = new CustomerEntity(customerId);
    using (var adapter = new DataAccessAdapter())
    {
        adapter.FetchEntity(customer);
    }

    return customer;
}

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 02-Apr-2015 17:58:44   

This is sadly a side effect of how things are implemented. 'By design' is a dirty word as it's not really intentional, but not really solveable either.

The issue is that if you do:

order.Customer = GetCustomer(order.CustomerId);   // A
order.Customer = GetCustomer(order.CustomerId);   // B

on line B the entity instance assigned in line A is dereferenced first. It is done without looking at the instance which might be set. So here it will reset the FK field to null. Then the instance set on line B is assigned as related entity and the FK is synced again, which means a change.

It doesn't keep track of the values the FK field has had in the past, so e.g. you go from 1 to null to 1, it will see it as a change, not as a 'revert to original value. Hence the IsDirty flag being set.

You run into problems with this particular side effect?

Frans Bouma | Lead developer LLBLGen Pro
hotchill avatar
hotchill
User
Posts: 180
Joined: 22-Jan-2007
# Posted on: 02-Apr-2015 22:18:45   

Thanks.

We keep track of changes to users. When IsDirty flag is raised, we set UpdateDate and UpdateByUserId properties of user entity before saving. We noticed a lof of user entities with a more recent UpdatedDate than the VersionDate of the latest version. That made us worried we had a bug in the versioning trigger, but now we know what the problem is and will handle it in code by checking before setting the Manager property. This check actually saves a db roundtrip so it is worthwhile having.