none
Typecasting Anonymous types returned from functions that return dynamic entities from LinqToSQL RRS feed

  • Question

  • I posted before about how to pass back an anonymous variable from a function that does a LINQtoSQL join.  It turned out the resultset could not be passed back because the typedefinition assigned to it didn't have a name, and the compiler didn't let you define functions with a var return type

    But, it also turns out that you CAN pass a var back as a return type defined as an object.  AND, you can typecast that returned object against a sample definition using generics.  Below is an example that works for typecasting a resultset from a joined query in another function as a list with the same field definitions.  I would like to extend this to Lookups, but am having trouble with passing the definition for what the Lookup key should be.  I keep getting:

    Cannot convert lambda expression to type 'AnonymousType#1' because it is not a delegate type

    Any suggestions on how to get the key to  CreateLookupType()?

     

    //get some dynamically defined data
    var objMysteryAnonymousType = joinSomeDataUsingLINQtoSQL(); 
    
    // create an example of how the resultset should look like
    var myExpectedTypeDefinition = new {Pers_PersonId = 0,
    	                Pers_FirstName = "",
    			            Pers_LastName = "",
    			            Addr_Address1 = "",
    			            Addr_City = "",
    			            Addr_State = "",
    			            Comp_Name = ""};	
    			          
    //create an empty List to hold the resultset according to its typedefinition			            
    var ListTypeDefinitionTemplate = myExpectedTypeDefinition.CreateListType(); 
    //turn the returned Anonymous variable back into an objContacts thing
    var objContacts = objMysteryAnonymousType.CastToTypeOf(ListTypeDefinitionTemplate); 
    
    //now use it anyway you want....
    foreach(var c in objContacts)
    {
    	Console.WriteLine(c.Pers_PersonId.ToString() + " " + c.Pers_LastName);
    }
    
    //I want to do the same for Lookup, but how?...
    //Next line results in: Cannot convert lambda expression to type 'AnonymousType#1' because it is not a delegate type
    var LookupTypeDefinitionTemplate = myExpectedTypeDefinition.CreateLookupType(x => x.Pers_PersonId);
    var objMoreContacts = objMysteryAnonymousType.CastToTypeOf(LookupTypeDefinitionTemplate);
    
    
    
    public Object getSomeDataUsingLINQtoSQL()
    {
      var objContacts = (from objPerson in Persons
    	join a in Addresses
    	on objPerson.Pers_PrimaryAddressId equals a.Addr_AddressId
    	into grpAddress
    	from objAddress in grpAddress.DefaultIfEmpty()
    	join c in Companies
    	on objPerson.Pers_CompanyId equals c.Comp_CompanyId
    	into grpCompany
    	from objCompany in grpCompany.DefaultIfEmpty()
    	where(object.Equals(objPerson.Pers_PersonId,6) ||
    	   object.Equals(objPerson.Pers_PersonId,4))
    	orderby objPerson.Pers_LastName
    	select new { objPerson.Pers_PersonId,
    	       objPerson.Pers_FirstName,
    			   objPerson.Pers_LastName,
    			   objAddress.Addr_Address1,
    			   objAddress.Addr_City,
    			   objAddress.Addr_State,
    			   objCompany.Comp_Name});
    				 
    	return objContacts;		//this is an anonymous variable	 
    }
    
    
    public static class LINQtoDatasetHelperClass
    {
    
      //typecast an object using generics, so the casting matches an example
    	public static T CastToTypeOf<T>(this object objectToCast, T exampleType)
    	{
    		return (T)objectToCast;
    	} //EOF CastToTypeOf	
    	//typecast a LINQ List to contain a collection that matches the structure of an example	
    	public static IEnumerable<T> CreateListType<T>(this T prototype)
    	{
    	 return new List<T>();
    	}//EOF CreateListType
    	
    	//should this work?
    	public static IEnumerable<T> CreateLookupType<T>(this T prototype, T theKey )
    	{
    	 return new Lookup<theKey, prototype>();
    	}//EOF CreateLookupType
    }
    

    Tuesday, July 19, 2011 6:55 PM

All replies

  • Hi,

    Welcome!

    >>>myExpectedTypeDefinition.CreateLookupType(x => x.Pers_PersonId);
    CreateLookupType method just has one parameter (T), you couldn't pass in a lambda expression.

    http://msdn.microsoft.com/en-us/library/bb460184.aspx

    You should add method to transform Anonymous type to Lookup.

    Key can be : Pers_PersonId, the Value will be the element.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, July 20, 2011 6:24 AM
    Moderator
  • Hi Alan,

    Thanks for replying to my post.

    What I'm trying to do is to restore the type definition of an anonymous variable to what it ALREADY holds using generics- I don't want to transform it FROM something else INTO a lookup type.  I'm creating a set of functions that will allow anonymous variables with dynamic entities to be transported between functions without the need to hardcode extra classes just to define their structures.

    The  .CreateListType() function in this previous post does such typecasting for an anonymous variable that holds a list.  I'm trying to model .CreateLookupType() after CreateListType to do the same for anonymous variables that have lookups which were returned from called functions.  The returntype of the called function will be Object, so the type definition of its lookup will be lost in the passback.

    Ultimately, this group of helper functions will allow me to return resultsets to caller functions that were created from joins in called functions by re-casting them in the called function, without transforming the passed content.  For LinqToSQL, there are really only two possible results.  Resultsets can be either dynamic (LIST) where records are read only when the resultset is walked, or static (LOOKUP) where the resultset contains a copy of all the retrieved records.  The called function will have the responsibility of converting the resultset to a Lookup or a List.  My understanding is that if no ToLookup() or ToList() is used on the select, the resultset will be a LIST of some kind.

    I'm fairly new to LINQ and I've previously read  http://msdn.microsoft.com/en-us/library/bb460184.aspx.  I just don't understand what it is trying to say.

    I already tried to pass the name of the key (not its value) without a Lambda expression as:

    myExpectedTypeDefinition.CreateLookupType(Pers_PersonId);

    and got:

    The name 'Pers_PersonId' does not exist in the current context

    even though the name DOES appear in myExpectedTypeDefinition....

    And, if I specify x=> x.Pers_PersonId, I get the delegate error.

     

    As far as the documentation goes, I found it really confusing - I don't know what it means:

    public class Lookup<TKey, TElement> : ILookup<TKey, TElement>,
    IEnumerable<IGrouping<TKey, TElement>>, IEnumerable

    From what I can read, it's saying Lookup takes two parameters of type T, one of which is the fieldname of a key in the definition of another type represented by TElement.  Beats me how this signature is supposed to be translated to X => X.fieldname which has no commas, is a single parameter, and essentially means the same thing.

    The :ILookup part says that Lookup implements a lookup interface that also has the same parameter requirements.  Except, what on earth is the IEnumerable<IGrouping<TKey, TElement>>, IEnumerable that follows after it - a third parameter?

    After reading the document, I'm left with the feeling that Lookup can take anywhere between 1 and 3 parameters.

    Can you enlighten me?

     

    Wednesday, July 20, 2011 2:36 PM
  • Okay, so

    public class Lookup<TKey, TElement> : ILookup<TKey, TElement>,


                                                              IEnumerable<IGrouping<TKey, TElement>>,

                                                              IEnumerable

    is

    function signature (positional parameters) : interface definitions 1 through 3

    and it really means Lookup normally takes two positional parameters, the first is a key and the second is the structure the key exists within.

    The other two say that Lookup can also behave as an enumerator, and it can walk through sub groups of records or it can walk the entire recordset.

     

    My CreateLookupType function takes one parameter, which is the fieldname for the key.  The method is attached to the structure definition the key exists in: 

     public static IEnumerable<T> CreateLookupType<T>(this T prototype, T theKey )
    {
    return new Lookup<theKey, prototype>();
    }//EOF CreateLookupType

    So, this function should be okay and work.  The real question is how do I specify the key when I do the call to CreateLookupType without using a Lambda expression, or how do I specify theKey parameter so that it accepts a Lambda expression?

     

     

     

    Wednesday, July 20, 2011 3:01 PM
  • Hi,

    There is ToLookup extension method: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.tolookup.aspx

          using (var context= new EFTestEntities())
          {
            var test = context.Employees.ToLookup(e => e.EmployeeId, e=>e);
          }
    

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, July 27, 2011 9:24 AM
    Moderator
  • Hi,

    I am writing to check the status of the issue on your side.  Would you mind letting us know the result of the suggestions?

    If you need further assistance, please feel free to let me know.   I will be more than happy to be of assistance.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, August 2, 2011 3:51 PM
    Moderator
  • I haven't had a chance to apply ToLookup, however, I can see that your suggestion would work as the LINQ extensions I've talked about are essentially equivalent to a ToList function (they produce a list from an input source that is typecast according to a model of another list).

    I'm fairly new to LINQ and still don't have an understanding of its underlying mechanics.  I was looking for a way to pass resultsets between functions so that everything didn't have to be written in one spot, and that similar code blocks could be reused without much additional coding.

    I thought that LINQ resultsets were one of four types, with LOOKUP being one of them.  But, LOOKUP is essentially a LIST with the restriction that duplicate records/keys could not exist in it.  This made using a LOOKUP to pass results between functions problematic as it meant any logic that used it would have to ensure there were no duplicate keys.  This would be an additonal layer of processing that had nothing to do with passing results, so I opted NOT to have a LOOKUP version of the result passing logic.  Any LIST with unique keys could be converted to a LOOKUP if needed in a function that recieved such a list.

    Tuesday, August 2, 2011 4:03 PM