none
Linq: Returning a single property instead of the entire entity

    Question

  • I am trying to write a linq query against a .Net 4.0 WCF Data Service that enumerates a single property from the entity, intead of the entire entity:

    InfoReturnEntities context = new InfoReturnEntities(new Uri("http://host/InfoReturnData.svc"));
    
          IEnumerable<int> years = (from iry in context.InfoReturnYears
                 orderby iry.Year descending
                 select iry.Year );
    
          foreach (int iry in years)
          {
            Console.WriteLine(iry.ToString());
          }
    

    This fails with the error:

    Error translating Linq expression to URI: Can only specify query options (orderby, where, take, skip) after last navigation.

    Changing the query to:

    InfoReturnEntities context = new InfoReturnEntities(new Uri("http://host/InfoReturnData.svc"));
    
          IEnumerable<int> years = (from iry in context.InfoReturnYears
                 select iry.Year );
    
          foreach (int iry in years)
          {
            Console.WriteLine(iry.ToString());
          }
    

    Fails with the error:

    Navigation properties can only be selected from a single resource. Specify a key predicate to restrict the entity set to a single instance.

    I have seen the following post from an earlier version back in 2008:

    http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/thread/14bd3556-940a-432e-94ea-5d8f6a9c7455/

    I would have thought this would have been fixed by now, especially considering projections are now supported.  For example, the following code works fine:

    InfoReturnEntities context = new InfoReturnEntities(new Uri("http://host/InfoReturnData.svc"));
    
          var years = (from iry in context.InfoReturnYears
                 orderby iry.Year descending
                 select new {Year = iry.Year} );
    
          foreach (var iry in years)
          {
            Console.WriteLine(iry.Year.ToString());
          }
    

    Are we still waiting for this feature to be implemented, or am I missing something?

    Thanks,

    Chris 

    Wednesday, March 09, 2011 3:17 AM

Answers

  • Hi,

    The projections feature is a little bit different. It stillr eturns the entity, it just doesn't send all it's properties. That's why the client LINQ still requires an object to be projected and not just a single property. So in short, what you're asking for is not yet supported (mainly because the OData protocol doesn't have a way to express such query). You can work around it using projections the way you did, or if you want to have a single query you can do:
    (from iry in context.InfoReturnYears
    orderby iry.Year descending
    select new { Year = iry. Year }).AsEnumerable().Select(t => t.Year);

    The AsEnumerable means, run everything before this as an OData query and do everything after it on the client side. So it's effectively very similar to your foreach, but it does everything in one LINQ query.

    Thanks,


    Vitek Karas [MSFT]
    • Marked as answer by Chris Coulson Wednesday, March 09, 2011 2:31 PM
    Wednesday, March 09, 2011 7:56 AM
    Moderator

All replies

  • Hi,

    The projections feature is a little bit different. It stillr eturns the entity, it just doesn't send all it's properties. That's why the client LINQ still requires an object to be projected and not just a single property. So in short, what you're asking for is not yet supported (mainly because the OData protocol doesn't have a way to express such query). You can work around it using projections the way you did, or if you want to have a single query you can do:
    (from iry in context.InfoReturnYears
    orderby iry.Year descending
    select new { Year = iry. Year }).AsEnumerable().Select(t => t.Year);

    The AsEnumerable means, run everything before this as an OData query and do everything after it on the client side. So it's effectively very similar to your foreach, but it does everything in one LINQ query.

    Thanks,


    Vitek Karas [MSFT]
    • Marked as answer by Chris Coulson Wednesday, March 09, 2011 2:31 PM
    Wednesday, March 09, 2011 7:56 AM
    Moderator
  • Greetings Chris,

    I found some code in the book Pro LINQ Object Relational Mapping with C# 2008 where the author appears to be returning a single value from the database: 

    // Create new database context
    AdventureWorksDataContext db = new AdventureWorksDataContext();

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        if (txtLastName.Text.Trim().Length == 0
            || txtVacationHours.Text.Trim().Length == 0)
        {
            MessageBox.Show("Please enter values for all text boxes");
        }
        else
        {
            try
            {

                Employee emp =
                db.Employees.Single(r => r.Contact.LastName == txtLastName.Text);
                emp.VacationHours = short.Parse(txtVacationHours.Text);
                db.SubmitChanges();
                MessageBox.Show("Update succcessful");
            }
            catch(Exception ex)
            {
                throw ex;

            }

        }
    }

    I believe the bold text returns a single value based on the lamda expression.  The Single method will raise an error if more than a single value is returned.  Pretty sweet as there a lot of times when I want just a value without all of the properties of an entity.  More info on this method can be found:  http://msdn.microsoft.com/en-us/library/bb907934(v=vs.90).aspx.  Hope this helps. 

    Darryl

    Tuesday, January 10, 2012 2:23 PM
  • Unfortunately .Single LINQ operator is not supported by the WCF DS Client LINQ implementation (mainly because it's not always easy to translate that to the OData query language).

    Thanks,


    Vitek Karas [MSFT]
    Tuesday, January 10, 2012 4:15 PM
    Moderator
  • Hi ,

    You want to return all yur datacontext or what?


    So B
    Wednesday, January 11, 2012 3:54 PM