Shion
Shion

Reputation: 1499

LINQ inheritance "Down-Cast" with a new Property

I have the following two classes:

public class Base
{
    public int Id { get; set; }
    public string PropertyA { get; set; }
}

[NotMapped]
public class Derived : Base
{
    public string PropertyB { get; set; }
}

And I have the following Query:

var baseQ = from b in db.Bases
            let propertyB = SomeCalculation()
            select new { Base = b, PropertyB = propertyB };

This works as is. What i want is something like this (Pseudo-Code):

List<Derived> list =  (from b in db.Bases
                      let propertyB = SomeCalculation()
                      select new { Base = b, PropertyB = propertyB }).ToList();

Is it possible to "Down-Cast" the selection to a derived class, or do I have to write a Constructor for the Derived class which looks something like this:

public Derived(Base b, string b) { ... }

My final solution: I changed the Derived Class to the following (since you even can't use a string.Format in the object initializer):

public class Derived
{
    public Base Base { get; set; }
    public string PropertyB { get; set; }

    public string CalculatedProperty { get { ... } }//For string.Format and other stuff
}

And I'm doing the assignement as follows:

List<Derived> list =  (from b in db.Bases
                      let propertyB = SomeCalculation()
                      select new Derived { Base = b, PropertyB = propertyB }).ToList();

Upvotes: 2

Views: 2305

Answers (3)

Kirk Broadhurst
Kirk Broadhurst

Reputation: 28698

The accepted answer won't work because EF won't let you construct concrete types in the database. The workaround - it does allow you to select anonymous types.

Building on Ahmad's answer:

var aList = (from b in db.Bases
             let propertyB = SomeCalculation()
             select new 
             {
                 Id = b.Id,
                 PropertyA = b.PropertyA,
                 PropertyB = propertyB
             }).ToList(); 

List<Derived> list = (from a in aList
                      select new Derived
                      {
                          Id = a.Id,
                          PropertyA = a.PropertyA,
                          PropertyB = a.PropertyB
                      }).ToList(); 

Calling ToList on your query forces the query to be executed and the data to be retrieved into your application (i.e. it will no longer be executed in the database). aList is now a list in memory, so you can select the items into new Derived objects.

In simplest terms, the problem is that everything up until you call ToList is compiled into a SQL query (to improve efficiency). This is normally a good thing, but the issue is that your database has no concept of Derived and the query select new Derived can't be converted into SQL.

Upvotes: 0

Reza ArabQaeni
Reza ArabQaeni

Reputation: 4907

List<Derived> list = db.Bases.ToList()
.Select(p => new Derived()
                 {
                     Id = b.Id,
                     PropertyA = b.PropertyA,
                     PropertyB =  SomeCalculation(),
                 }).ToList();;

Upvotes: 1

Ahmad Mageed
Ahmad Mageed

Reputation: 96477

You can't cast in this case since what your query returns is an anonymous type. Instead, you could use an object initializer to set the properties to the Derived class:

List<Derived> list = (from b in db.Bases
                     let propertyB = SomeCalculation()
                     select new Derived
                     {
                         Id = b.Id,
                         PropertyA = b.PropertyA,
                         PropertyB = propertyB
                     }).ToList();

If you have a ton of properties you could take the approach you suggested, or add a Data Transfer Object (DTO) that contains your properties, then use a library like AutoMapper to perform the mapping for you.

Upvotes: 3

Related Questions