UpdateEntitiesDirectly - Wierdest One Yet

Posts   
 
    
Marcus avatar
Marcus
User
Posts: 747
Joined: 23-Apr-2004
# Posted on: 06-May-2005 12:40:45   

Frans,

I don't even know where to start on this one!

After calling the following line of code, rowsAffected is = 1... but nothing hits the database. confused

rowsAffected = Adapter.UpdateEntitiesDirectly(folderLinkEntity, filter);

I'm stepping through the code on one side and looking at SQL Profiler on the other side. No SQL is sent to the db.

Any ideas on where to start looking?

UPDATE: BTW I havent had an opportunity to upgrade to 2004.2 yet... So this is 2004.1

Marcus

Full method:

protected override IResponse DoExecute(IRequest request)
{
    MoveFolderRequestType req = CastRequest(request);

    FolderLinkEntity folderLinkEntity = new FolderLinkEntity();
    folderLinkEntity.ChildFolderUID = req.FolderUID;
    folderLinkEntity.ParentFolderUID = req.NewParentFolderUID;

    IRelationPredicateBucket filter = new RelationPredicateBucket();
    filter.PredicateExpression.Add(PredicateFactory.CompareValue(FolderLinkFieldIndex.ParentFolderUID, ComparisonOperator.Equal, req.OldParentFolderUID));
    filter.PredicateExpression.Add(PredicateFactory.CompareValue(FolderLinkFieldIndex.ChildFolderUID, ComparisonOperator.Equal, req.FolderUID));

    int rowsAffected;
    try
    {
        rowsAffected = Adapter.UpdateEntitiesDirectly(folderLinkEntity, filter);
    }
    catch(SqlException ex)
    {
        if (ex.Number == 2627) { // Violation of PRIMARY KEY constraint
            throw new SdsAlreadyExistsException("The folder already exists at the destination.", ex);
        } else
        {
            throw;
        }
    }

    if (rowsAffected != 1)
    {
        Log.Warn(string.Format("Move FolderUID '{0}' failed. Attempted to move from '{1}' to '{2}' but rows affected was {3}", req.FolderUID, req.OldParentFolderUID, req.NewParentFolderUID, rowsAffected));
        throw new SdsNotFoundException("Either the folder no longer exists, or it has already been moved by another user.");
    }

    return CreateResponseObject();
}

Marcus avatar
Marcus
User
Posts: 747
Joined: 23-Apr-2004
# Posted on: 06-May-2005 12:58:53   

Not sure if this relevant, I am attempting to update the PK of this table...

Marcus avatar
Marcus
User
Posts: 747
Joined: 23-Apr-2004
# Posted on: 06-May-2005 13:06:11   

I think I know what's wrong...

In ActionQuery you check:


public int Execute(){
...
// check if there is something to execute
if(base.Command.CommandText.Length==0)
{
    // no. return 'succeeded' (1 row affected at least)
    return 1;

}
...
}

It would appear that since I'm not modifying any of the table's fields other than the PK, the CommandText is empty...

UPDATE: Yes:


private static void ConstructFieldsToUpdateList(IEntityFieldCore[] fields, IFieldPersistenceInfo[] fieldsPersistenceInfo, ref ArrayList fieldsToUpdate, ref ArrayList persistenceInfoFieldsToUpdate)
{
    for(int i = 0; i < fields.Length; i++)
    {
        if(fields[i].IsChanged || (fields[i].ExpressionToApply!=null))
        {
            if(fields[i].IsPrimaryKey && fields[i].DbValue==null)
            {
                // changed PK field, do not update this field
                continue;
            }
            if(fieldsPersistenceInfo[i].IsIdentity)
            {
                continue;
            }

            // field can be updated
            fieldsToUpdate.Add(fields[i]);
            persistenceInfoFieldsToUpdate.Add(fieldsPersistenceInfo[i]);
        }
    }
}

Why can you not change the PK? cry

Marcus

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39928
Joined: 17-Aug-2003
# Posted on: 06-May-2005 13:23:49   

You can actually simple_smile

The problem is, the code generating the query has to formulate a filter on the PK. (to find the row to alter). If you just set the PK field of a new entity, it will think (it has to) that the PK set in the entity is the one to use for the filter.

To ALTER a PK, you have to alter an existing's entity's PK field. This way, DbValue is set as well. This then means that the query generator can find back the row to alter. You run into a check in FieldCompareValuePredicate, where it tries to determine which value to use.

Please see this unittest which illustrates how to alter a PK in the database:


[Test]
public void UpdatePkTest()
{
    DataAccessAdapter adapter = new DataAccessAdapter();

    try
    {
        ProductEntity newProduct = EntityCreator.CreateNewProduct(1);
        newProduct.TestRunId = _testRunID;
        Console.WriteLine("Current Product PK = {0}", newProduct.ProductId.ToString());
        bool result = adapter.SaveEntity(newProduct, true);
        Assert.IsTrue(result);

        // alter PK
        newProduct.ProductId = Guid.NewGuid();
        Console.WriteLine("New Product PK = {0}", newProduct.ProductId.ToString());
        
        // resave the product.
        result = adapter.SaveEntity(newProduct, false);
        Assert.IsTrue(result);
    }
    finally
    {
        adapter.Dispose();
    }
}

Frans Bouma | Lead developer LLBLGen Pro
Marcus avatar
Marcus
User
Posts: 747
Joined: 23-Apr-2004
# Posted on: 06-May-2005 13:36:26   

So I have to fetch it first... mmmm disappointed

Yes I can see now why you've done it this way. I was passing the filter myself along with the new PK values.

I think I'll write a Store Procedure to do it simple_smile . Call me picky but as my accountant always says: "look after the pennies and the pounds will look after themselves". i.e. Never use two queries when you all you need is one.

Thanks. Marcus

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39928
Joined: 17-Aug-2003
# Posted on: 06-May-2005 13:43:59   

You can of course also cheat, Marcus! smile

Set the DbValue to the original value, and the current value to the new value, then set the ischanged flag:

folderLinkEntity.Fields["FolderUID"].ForcedCurrentValueWrite(newvalue, oldvalue); folderLinkEntity.Fields["FolderUID"].IsChanged=true;

(if FolderUID is the PK of course wink )

(from my bare head, haven't tested this, but it should work. If not, I'll dig deeper into the code, to see why not)

Frans Bouma | Lead developer LLBLGen Pro
Marcus avatar
Marcus
User
Posts: 747
Joined: 23-Apr-2004
# Posted on: 06-May-2005 13:55:07   

Now that's why I use LLBLGen smile

Top marks!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39928
Joined: 17-Aug-2003
# Posted on: 06-May-2005 14:46:43   

smile

Frans Bouma | Lead developer LLBLGen Pro