views:

84

answers:

2

This is weird ... done updates loads of times before but cannot spot why this is different. although I am using .net 4.0 now - however i doubt its a bug in its L2S implementation. Its not like this is a wierd and wonderful application of it. Although i am fairly sure this code worked whilst i was using the RC.

I have also managed to reproduce this error by building a project from scratch using the information below.

the problem here is that the update statement generated by L2S has no fields in the set statement. I have tried checking the that the pk is set (only reason why i would think ervery field would be required in the where) and also read aroudn the other dbml properties. I have been using linq2Sql for about 1 year and have never had a problem .. i still think i am just having a huge brain fart.

Note: I have cleaned up the equals and GetHashCode methods to remove some fields - the problem persists after this. I have not cleaned up the SQL though.

I have a client class from the dbml I added a method called update

public partial class Client :  ICopyToMe<Client>

The CopyToMe method is inherited from an interface

   public  interface ICopyToMe<T>
    {
        void CopyToMe(T theObject);
    }

also the class has getHashCode overridden

public override int GetHashCode()
{
    int retVal = 13 ^ ID ^ name.GetHashCode();
    return retVal;
}

and equals

public override bool Equals(object obj)
{
    bool retVal = false;
    Client c = obj as Client;
    if (c != null)
        if (c.ID == this.ID && c._name == this._name)
            retVal = true;
    return retVal;
} 

the update method in the partial class

 public void UpdateSingle()
        {          
            L2SDataContext dc = new L2SDataContext();
            Client c = dc.Clients.Single<Client>(p => p.ID == this.ID);
            c.CopyToMe(this);
            c.updatedOn = DateTime.Now;

            dc.SubmitChanges();
            dc.Dispose();
                        }

The CopytoMe method

 public void CopyToMe(Client theObject)
        {
            ID = theObject.ID;
            name = theObject.name;                
        }

Im taking a client that was selected, changing its name and then calling this update method. The generated sql is as follows

exec sp_executesql N'UPDATE [dbo].[tblClient]
SET 
WHERE ([ID] = @p0) AND ([name] = @p1) AND ([insertedOn] = @p2) AND ([insertedBy] = @p3) AND ([updatedOn] = @p4) AND ([updatedBy] = @p5) 
AND ([deletedOn] IS NULL) AND ([deletedBy] IS NULL) AND (NOT ([deleted] = 1))',N'@p0 int,@p1 varchar(8000),@p2 datetime,@p3 int,@p4 
datetime,@p5 int',@p0=103,@p1='UnitTestClient',@p2=''2010-05-17 11:33:22:520'',@p3=3,@p4=''2010-05-17 11:33:22:520'',@p5=3

I have no idea why this is not working ... used this kind of

select object -> set field to new value -> submit the selected object

pattern many times and not had this problem. there is also nothing obviously wrong with the dbml - although this is probably a false statement

any ideas?

This problem make sit look like i'm going to have to revert back to ADO.Net which would make me sad.

A: 

If that exact UPDATE statement is sent to the database (without any SET arguments), then you found a bug in LINQ to SQL. Try your code in .NET 4.0 and if it still fails, submit a bug to the Microsoft connect site.

Anne Sharp
+1. I didn't spot the query was invalid. I didn't really understand what the OP was asking.
Steven
this is .net 4.0 ... missed that teeny weeny insignificant detail .. i have actually taken this code from a 3.5 project that i was converting ... i am 99.99% sure this code worked perfectly fine then.
John Nicholas
however i added the overrides since then which is why it is broke.
John Nicholas
A: 

OK after some discussions with some very helpful microsoft people I have found the answer to this problem.

Linq uses the Hash code to index its collections in a hash table. This means that the hash code function needs to work only on the fields that uniquely identify the object.

In this case the Hash can only work on the ID column. As such GetHashCode will always return the same value for records with the same primary key even if their data is different.

Equals on the other hand can test accross a larger number of fields - ie its test is more specific than GetHashCode comparisons.

If you make the GetHashCode function cover more fields than the primary keys then linq2sql will loose track of the object and so will behave very strangely.

John Nicholas