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 CopytoM开发者_开发技巧e 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.
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.
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.
精彩评论