Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / New Users / September 2007

Tip: Looking for answers? Try searching our database.

Strange results attempting IDENTITY in LINQ

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Kevin_E - 25 Sep 2007 01:30 GMT
I tried to add an one-up sequence to a LINQ select such as:

var i = 0;
var tokenized =
from line in lines
select new {
    index = (i = i + 1)
    ,tokens = line.Split(new char[] {' '}
}

However, I get strange, but somewhat explainable results.  It seems that
every time I access 'index' above the value increments.  It is behaving as if
the code was assigned to the member and not the value.  I have tried many
different ways to
reduce the result to a value without much success:

index = Convert.ToInt32((new int[] {i=i+1})[0].ToString())

in C# I defined a class for holding the values:

Tokenized
{
    :
    public int Index() { get {return _index; }}
    :
}
and assigned _index using a static value at construction.  And still saw the
same issue.

The objective was to assign values to each line so that they could be
refered to directly in later queries.  But since the values keep changing,
this does not work.

This is a cool and interesting feature and I can think of many uses for
this, but it is irritating in that I can't seem to find a way to force it to
take the value rather than the expression.

Can someone tell me how to set up the equivalent of IDENTITY(1,1) in LINQ?
Kevin_E - 25 Sep 2007 02:02 GMT
Code to reproduce in LinqPAD:

//var lines = File.ReadAllLines(@"C:\Documents and Settings\kenglish\My
Documents\Genealogy\Hans Ancestry.GED");
var lines = new string[] {
"0 HEAD"
,"1 CHAR ANSI"
,"1 SOUR Ancestry.com Family Trees"
,"2 VERS Ancestry.com Family Trees (1)"
,"2 NAME Ancestry.com Family Trees"
,"2 CORP The Generations Network"
,"1 GEDC"
,"2 VERS 5.5"
,"2 FORM LINEAGE-LINKED"
,"0 @P2570715294@ INDI "
,"1 SEX F"
,"1 NAME Catharina"
,"1 FAMS @F198@"
,"0 @P2577568933@ INDI "
,"1 BIRT "
,"2 DATE 1515"
,"2 PLAC Cambridge,,Kent,England"
,"1 DEAT "
,"2 DATE 1590"
,"2 PLAC Cambridge,,Kent,England"
,"1 SEX F"
,"1 NAME John /Fosten/"
,"1 FAMS @F252@"
};

var i = Convert.ToInt32(0);

var tokenized =
from line in lines
select new {
           index = (new int[] {i, i=i+1, i+2}).Min()
           ,tokens = line.Split(new char[] {' '})
           ,depth = Convert.ToInt32(line.Split(new char[]{' '})[0])
};

tokenized.Dump();

var tokenized2 =
from tl in tokenized
select new {
    index = tl.index
    ,depth = tl.depth
    ,tokens = tl.tokens
    ,prevDepth = (tokenized.Where(L2 => L2.index == (tl.index-1)))
};

tokenized2.Dump();

Note that the first select has index values of: 0,1,2,...22
and the second select has index values of: 23, 47, 71, ...551
as if each iteration of the where clause incremented the index value.
Lloyd Dupont - 25 Sep 2007 04:16 GMT
There is nothing wrong here, user error again.
You declare 'i' at the top level.

A simplified version of your error would be:

== pseudo code with the same "error" ===

int i = 0;
foreach(var v in something)
   i ++;
foreach(var v in something)
   i ++;

====
at the end, as expected, i = something.Count * 2
Signature

Regards,
Lloyd Dupont
NovaMind Software
Mind Mapping at its best
www.nova-mind.com

> Code to reproduce in LinqPAD:
>
[quoted text clipped - 52 lines]
> and the second select has index values of: 23, 47, 71, ...551
> as if each iteration of the where clause incremented the index value.
Lloyd Dupont - 25 Sep 2007 04:22 GMT
Oops, sorry, I just understand your problem.

Good point indeed.

But, after short reflection, it seems to be inline with what I read
somewhere (and can't find again) that LINQ query are evaluated on demand (as
opposed to store in an invisible variable)

Hence it is evaluated a second time in the second statement, so that it can
be enumerated.
Lloyd Dupont - 25 Sep 2007 04:49 GMT
Correction
> Hence it is evaluated a second time in the second statement, so that it
> can be enumerated.

Hence it is evaluated a second time in the second statement AS IT IS
enumerated.
Kevin_E - 25 Sep 2007 04:50 GMT
Yep, I think that is what I am seeing.

So I guess my question should be is there any way to force the evaluation or
scalarization of the expression so that the first result just contains the
values?

I've tried all kinds of things.  I thought for sure that :

   index = (new int[] {i, i=i+1, i+2}).Min()

would work ... but it did not.

> Oops, sorry, I just understand your problem.
>
[quoted text clipped - 6 lines]
> Hence it is evaluated a second time in the second statement, so that it can
> be enumerated.
Lloyd Dupont - 25 Sep 2007 04:59 GMT
> So I guess my question should be is there any way to force the evaluation
> or
> scalarization of the expression so that the first result just contains the
> values?

Well, with anonymous type I don't know.
But if you return a known type, how about something like

List<Result> results = new List<Result>(from .....);

as in
==================
class Program
{
 class Result
 {
  public int Index;
  public string Text;
  public override string ToString()
  {
   return string.Concat("Result: ", Index, " ", Text);
  }
 }

 static void Main(string[] args)
 {
  var lines = new string[] {
    "0 HEAD"
   ,"1 CHAR ANSI"
   ,"1 SOUR Ancestry.com Family Trees"
   ,"2 VERS Ancestry.com Family Trees (1)"
   ,"2 NAME Ancestry.com Family Trees"
   ,"2 CORP The Generations Network"
   ,"1 GEDC"
   ,"2 VERS 5.5"
   ,"2 FORM LINEAGE-LINKED"
   ,"0 @P2570715294@ INDI "
   ,"1 SEX F"
   ,"1 NAME Catharina"
   ,"1 FAMS @F198@"
   ,"0 @P2577568933@ INDI "
   ,"1 BIRT "
   ,"2 DATE 1515"
   ,"2 PLAC Cambridge,,Kent,England"
   ,"1 DEAT "
   ,"2 DATE 1590"
   ,"2 PLAC Cambridge,,Kent,England"
   ,"1 SEX F"
   ,"1 NAME John /Fosten/"
   ,"1 FAMS @F252@"
   };

  int i = 0;
  List<Result> results = new List<Result>(from line in lines
            select new Result()
            {
             Index = i++,
             Text = line.Split(new char[] { ' ' })[1]
            });

  foreach (var v in results)
   Console.WriteLine(v);
  foreach (var v in results)
   Console.WriteLine(v);

  Console.ReadLine();
 }
}
==================
Jon Skeet [C# MVP] - 25 Sep 2007 08:45 GMT
> Code to reproduce in LinqPAD:

It's very straightforward. Each time you iterate through "tokenized" it
will increment i for each line.

Here's where you do it first:

  tokenized.Dump();

And here's where you do it again:

var tokenized2 =
 from tl in tokenized
 ...

You could avoid this by saving the results in a list:

var list = tokenized.ToList();

Then do:

  list.Dump();

var tokenized2 =
  from tl in list
  ...

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Lloyd Dupont - 25 Sep 2007 02:41 GMT
probably a user error....
here is my test program:
================
class Program
{
 static void Main(string[] args)
 {
  List<string> lines = new List<string>()
  {
   "e gweuir gwoergew roiwegrwel",
   "ewqhk few9p oi cowicn cnu",
   "le chien chat bouh",
   "a fish in the sky",
   "selamat paggi"
  };
  var i = 0;
  var tokenized = from line in lines
      select new
      {
       index = (i = i + 1),
       tokens = line.Split(new char[] { ' ' })
      };

  foreach (var v in tokenized)
   Console.WriteLine("{0}, {1}, {2}, {3}", v, v.index, v.index,
v.tokens[0]);

  Console.ReadLine();
 }
}
================
and its output
================
{ index = 1, tokens = System.String[] }, 1, 1, e
{ index = 2, tokens = System.String[] }, 2, 2, ewqhk
{ index = 3, tokens = System.String[] }, 3, 3, le
{ index = 4, tokens = System.String[] }, 4, 4, a
{ index = 5, tokens = System.String[] }, 5, 5, selamat
================

Signature

Regards,
Lloyd Dupont
NovaMind Software
Mind Mapping at its best
www.nova-mind.com

>I tried to add an one-up sequence to a LINQ select such as:
>
[quoted text clipped - 37 lines]
>
> Can someone tell me how to set up the equivalent of IDENTITY(1,1) in LINQ?
Kevin_E - 25 Sep 2007 03:02 GMT
It's not a user error it is very reproducable.  Your example does not use a
where clause to attempt to look up a record from a second query.  If you look
at the code I posted you will see that this is where things get strange.  The
results of my first select look completely normal.  It is when I try to
reference the value in a useful way that things go nuts.

> probably a user error....
> here is my test program:
[quoted text clipped - 77 lines]
> >
> > Can someone tell me how to set up the equivalent of IDENTITY(1,1) in LINQ?

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.