2

At first I had an IEnumerable object called "Employees" that had all of its properties mapped to a single class "Employee".

I passed the IEnumerable object Employee to a private method, that parsed through the properties and mapped it to a data-table.

   private void createEmployeesDataTable(IEnumerable<Employee> Employees)
    {
    .... stuff here to define the datatable ....

       foreach (var elem in Employees)
       {
           var row = dataTable.NewRow();
           row["Name"] = elem.JobTitle;
           row["Address"] = elem.Address;
           row["Phone"] = elem.Phone;
           row["DateOfHire"] = elem.HireDate;
           dataTable.Rows.Add(row);
       }
    }

Worked like a charm.

Now I have a bunch of classes, mapped to the database and an IQueryable object Employees. The code is simplistic.

    DataContext db = new DataContext(System.Configuration.ConfigurationManager.ConnectionStrings["employeeDB"].ConnectionString);
    Table<Employee> Emp = db.GetTable<Employee>();
    Table<Address> Add = db.GetTable<Address>();
    Table<BusinessEntityAddress> BE = db.GetTable<BusinessEntityAddress>();
    Table<Phone> Phone = db.GetTable<Phone>();
    Table<State> State = db.GetTable<State>();

    var Employees =
        from Employi in Emp
        join PhoneNumber in Phone on Employi.BusinessEntityID equals PhoneNumber.BusinessEntityID
        join BusEntity in BE on Employi.BusinessEntityID equals BusEntity.BusinessEntityID
        join Addy in Add on BusEntity.AddressID equals Addy.AddressID
        join StProv in State on Addy.StateProvinceID equals StProv.StateProvinceID
        where Employi.HireDate > userInputLimit
        select new {DateOfHire = Employi.HireDate, Address = Addy.AddressLine1 + Addy.City + StProv.StateProvinceCode + Addy.PostalCode,
                    Phone = PhoneNumber.PhoneNumber, Name = Employi.JobTitle};

Now I am passing this object to the private method, to create a Data-table, except I pass it as an IQueryable of anonymous type. The reason being, my object now has properties derived from multiple classes and no longer from a single, employee class:-

private void createEmployeesDataTable(IQueryable Employees)
        {
.... how can I still access all of its properties and bind it to the datatable?? .... 
}

When I put a breakpoint on the IQueryable Employees object, I can see it has all the property names and values correctly stored in it. But I cannot seem to access them via code....

A sample of my class:-

 [Table(Name="HumanResources.Employee")]
    public class Employee
    {
        private int _BusinessEntityID;
        [Column(IsPrimaryKey = true, CanBeNull=false, Storage = "_BusinessEntityID")]
        public int BusinessEntityID
        {
            get
            {
                return this._BusinessEntityID;
            }
            set
            {
                this._BusinessEntityID = value;
            }

        }

        private string _JobTitle;
        [Column(Storage = "_JobTitle", CanBeNull=false, DbType="nvarchar(50) NOT NULL")]
        public string JobTitle
        {
            get
            {
                return this._JobTitle;
            }
            set
            {
                this._JobTitle = value;
            }
        }


        private DateTime _HireDate;
        [Column(Storage = "_HireDate", CanBeNull=false)]
        public DateTime HireDate
        {
            get
            {
                return this._HireDate;
            }
            set
            {
                this._HireDate = value;
            }
        }
    }
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Philo
  • 1,931
  • 12
  • 39
  • 77
  • Pass as `IQueryable`. – Wiktor Zychla Sep 17 '15 at 19:00
  • 1
    @WiktorZychla OP is not passing in an `IQueryable` but an `IQueryable<{anonymoustype}>`. – D Stanley Sep 17 '15 at 19:03
  • @DStanley: exactly, he is not passing any concrete type while he should. The `Employee` would be a natural choice if he expects a similar set of properties as in his above example with `IEnumerable`. How to pass it is another story. – Wiktor Zychla Sep 17 '15 at 19:07
  • 1
    @WiktorZychla The anonymous type is pulling fields from several tables, not just `Employee`. – D Stanley Sep 17 '15 at 19:09
  • Stanley is right. The reason I am not passing a concrete type, is because my Employee class is no longer comprising of all properties I need. Now there are multiple classes, and I was hoping to learn a way where I can have the anonymous type and access properties from various different classes. – Philo Sep 17 '15 at 19:12
  • @DStanley: of course he is. His question is about using a non-generic IQueryable while he should be using a concrete type. My comment is a word to the wise that a generic version has to be used. Your answer adresses that in more details, you really don't have to explain it to me. – Wiktor Zychla Sep 17 '15 at 19:14
  • @Philo You can't if you want to pass it off to another method. When you use an anonymous type the compiler only knows about the fields _within that method_. – D Stanley Sep 17 '15 at 19:17
  • Hmm, why all these joins, don't you have a navigation properties in your `Employee` entity class? And just pass the result of the query converted to enumerable w/o projecting into anonymous type directly to your old method (as `IEnumerable`)? – Ivan Stoev Sep 17 '15 at 20:22
  • And if you don't, you better revisit your entity design. Entities don't have to be like db tables. Except the primary key, whenever you have a foreign key (like `AddressID`) you should have entity reference property (like `Address Address {get; set; }`. **EF** is intended to make the things easier, not harder as it seems in your question. – Ivan Stoev Sep 17 '15 at 20:42
  • I posted a sample of my Employee class. – Philo Sep 17 '15 at 20:45
  • Well, that's exactly what I meant. It lacks those (called navigation) properties like Phone, Address etc. which EF will automatically populate for you (when needed) w/o the need of writing joins at all. – Ivan Stoev Sep 17 '15 at 20:50
  • I know that's not exactly what you are asking for, but I don't see any reason to waste time on that concrete problem while a relatively simple design change would solve this and any similar problems in the future. If you insist on the concrete issue, may be someone else will help you - but definitely it wouldn't be me. Good luck. – Ivan Stoev Sep 17 '15 at 21:00
  • @IvanStoev Thank you for your help. I like your suggestion. But I am a beginner and dont understand the concept of navigation properties. Can you show me an example? – Philo Sep 17 '15 at 22:25
  • I apologize. Looks like you are using LINQ to SQL while all my comments are assuming Entity Framework. The accepted answer is just fine. Still I would recommend you to research Entity Framework at some point if you can afford - IMO it's much better and easier to use. – Ivan Stoev Sep 18 '15 at 06:59

1 Answers1

4

When I put a breakpoint on the IQueryable Employees object, I can see it has all the property names and values correctly stored in it. But I cannot seem to access them via code.

That's because the non-generic IQueryable interface knows nothing about the underlying types. You'd have to use the generic version (IQueryable<T>) to see the properties of the items at design-time.

However, since you're projecting to an anonymous type (and not a collection of Employee objects despite what you're named the variable), you don't know the type name at compile-time, so you can't specify the type T to use for IQueryable<T>.

The best solution would be to define a concrete type instead of using an anonymous on so that you can access the field at compile-time. You could use dynamic, but then you're delaying the property binding to run-time and won't catch any errors at compile-time.

The class definition would be something like:

public class EmployeeView
{
    public DateTime DateOfHire {get; set;}
    public string AddressLine1 {get; set;}
    public string City {get; set;}
    public string StateProvinceCode {get; set;}
    public string PostalCode {get; set;}
    public string Phone {get; set;}
    public string Name {get; set;}
}

and your projection would be:

select new EmployeeView {
    DateOfHire = Employi.HireDate, 
    AddressLine1 = Addy.AddressLine1,
    City = Addy.City,
    StateProvinceCode = StProv.StateProvinceCode,
    PostalCode = Addy.PostalCode,
    Phone = PhoneNumber.PhoneNumber, 
    Name = Employi.JobTitle};

Now you can specify the type in :

private void CreateEmployeesDataTable(IEnumerable<EmployeeView> employees)
{
    .... 
}

Note that I have changed the casing to .NET standards - classes with capitalized camel case and variables with lower-case camel case

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • That is incorrect. Using AsEnumerable() would enumerate the entire IQueryable all at once, and cause only one trip to the database. At that point enumerating a second time would be done in memory. So that would be orders of magnitudes better. – Travis J Sep 17 '15 at 19:15
  • 1
    @TravisJ: are you sure just enumerating an IQueryable with simple foreach causes a db roundtrip for each iteration? If you ask me, it doesn't. – Wiktor Zychla Sep 17 '15 at 19:17
  • 2
    @TravisJ No, `AsEnumerable` does _not_ execute the query - it just exposes it as an `IEnumerable` instead of an `IQueryable` so that any further Linq operations are bound to Ling-to-objects instead of Linq-to-{EF/SQL/whatever}. The query is not actually executed until it is enumerated (with `foreach, ToList`, etc.). The underlying object is still just a query, so iterating it multiple times will execute the query multiple times. If you _hydrate_ it using `ToList`, _THEN_ the data is fetched and will not go back to the DB (since the underlying object is a collection now, not a query. – D Stanley Sep 17 '15 at 19:19
  • @DStanley - You are correct, sorry for the confusion. AsEnumerable() does not in fact enumerate the query as I had thought. – Travis J Sep 17 '15 at 20:02
  • so how could I create a concrete type class with all the properties from the linq object? – Philo Sep 17 '15 at 20:39
  • @Philo I added an example to may answer. – D Stanley Sep 17 '15 at 21:23
  • Yea, after searching a bit, I figured I would create a master class that would consist of all the properties. – Philo Sep 17 '15 at 22:24