views:

174

answers:

1

Hello all,

I have a strange problem when deleteting records using linq, my suspicion is that it has something to do with the range variable (named source). After deleting a record all targets for a customer are retrieved using the following statement:

var q = from source in unitOfWork.GetRepository<db_Target>().Find()
  where source.db_TargetBase.db_Person.fk_Customer == customerID
  select source.FromLinq();

where FromLinq is in extention method on db_target:

public static Target FromLinq(this db_Target source)
{
    return new Target
    {
        id = source.id,
        LastModified = source.db_TargetBase.LastModified,
        ...
     }
}

When a record is deleted both db_Target and db_TargetBase are deleted. When, for example, two users are deleting records, linq tries to retrieve a record for user2 which is deleted by user1, causing a crash on the LastModified = source.db_TargetBase.LastModified line because db_TargetBase is null.

When using the following code the problem does not occure and only the non-deleted records are retrieved:

var q = from source in unitOfWork.GetRepository<db_Target>().Find()
    where source.db_TargetBase.db_Person.fk_Customer == customerID
    select new Target
    {
        id = source.id,
        LastModified = source.db_TargetBase.LastModified,
        ...
    };

This spawns two questions:

  1. What is happening here? Am I making a copy of the range variable source because I'm using it in a extention method?
  2. How can I "wrap" the return new Target code? I am using this in multiple places and do not want to copy it every time. Making my code harder to maintain.

TIA,

JJ

+1  A: 

In the first set of code - since the initializer lives an a non-translatable method (extension or otherwise), it cannot be translated - so it is run locally.

In the second set of code - the initializer is represented by an elementinit expression, which is translated (examine/compare the select clause of the generated sql for proof).


if you want to wrap this, you need to have an Expression<Func<db_Target, Target>> that anyone can grab and use in thier query. Fortunately, that's easy to do:

public Expression<Func<db_Target, Target>> GetFromLinqExpressionForTarget()
{
  return
    source => new Target
    {
      id = source.id,
      LastModified = source.db_TargetBase.LastModified,
      ...
    }
}

Which may be used like so:

var FromLinq = GetFromLinqExpressionForTarget();
var q =
(
   from source in ...
   ...
   ...
   select source
).Select(FromLinq);

Now ... I'm really running on a guess here and am only about 60% confident that my answer is correct. So if someone wants to confirm this, that'll make my day. :)

David B
Thanks for the respone, your explanation makes perfect sense to me.I'm on vacation right now, however, when I have the time I will test the implementation and give the appropriate feedback.