Subliminal Hash
Subliminal Hash

Reputation: 13744

Dynamic Linq Select with Lambda

The original question of mine is here. Where I was trying to find a way to restrict the number of columns returned FROM the database using Repository Pattern and Unit of Work. My question found an answer but I have not solved it and decided to post the new problem which arose using that technique as the problem I am going through now is a completely new subject.

In the repository, I have a Get method which takes the following parameters:

public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<TEntity, TEntity> selector = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")

The following works well inside of my controller:

IEnumerable<Models.Authors.Author> authors = unitOfWork.AuthorRepository.Get(filter: x => x.TenantID == 1);

But, I cannot get the 'select' part working:

IEnumerable<Models.Authors.Author> authors = unitOfWork.AuthorRepository.Get(filter: x => x.TenantID == 1, selector: a=> new { FirstName = a.FirstName } );

and similarly, this:

var authors = unitOfWork.AuthorRepository.Get(filter: x => x.TenantID == 1, selector: a=> new { FirstName = a.FirstName } );

gives the following two errors:

Cannot implicitly convert type '<anonymous type: string FirstName>' to 'Models.Authors.Author'

and

Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type

I am completely alien to this. So I would really appreciate your help..

UPDATED

this:

IEnumerable<Models.Authors.Author> authors = unitOfWork.AuthorRepository.Get(filter: x => x.TenantID == 1, selector: a=> new Models.Authors.Author() { FirstName = a.FirstName } );

gives this:

The entity or complex type 'DAL.Author' cannot be constructed in a LINQ to Entities query.

UPDATE 2: Author Class // namespace is

namespace Models.Authors
{
public class Author
{
    [Key]
    public int AuthorID { get; set; }
    public int CategoryID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhotoPath { get; set; }
    public byte[] PhotoBinary { get; set; }
    public string PhotoPathOriginal { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
    public Guid? PassGuid { get; set; }
    public string Email { get; set; }
    public string Twitter { get; set; }
    public string Facebook { get; set; }
    public DateTime? DateCreated { get; set; }
    public DateTime? DateLastlogin { get; set; }
    public int AuthorStatus { get; set; } // 0:inactive, 1:active, 2:suspended, 3:hidden etc.
    public string AboutAuthor { get; set; }
    public bool? RequirePublishApproval { get; set; }
    public string ColumnName { get; set; }
    public string ColumnImage { get; set; }
    public bool? ChangePassAtFirstLogin { get; set; }
    public int TenantID { get; set; }

    public virtual AuthorCategory AuthorCategory { get; set; }
    public virtual IQueryable<Post.Post> Posts { get; set; }
}
}

Upvotes: 0

Views: 656

Answers (1)

Pavel Morshenyuk
Pavel Morshenyuk

Reputation: 11471

You are asking repository to return for each records in the query result a new anonymous object:

selector: a => new { FirstName = a.FirstName }

But at the same time the variable you have declared is of type IEnumerable<Models.Authors.Author>

In order to make it work you need to return a Models.Authors.Author objects in a select:

IEnumerable<Models.Authors.Author> authors = unitOfWork.AuthorRepository.Get(filter: x => x.TenantID == 1, selector: a=> new Models.Authors.Author() { FirstName = a.FirstName } );

Alternatively you can use anonymous objects, but you need to declare variable as var

var authors = unitOfWork.AuthorRepository.Get(filter: x => x.TenantID == 1, selector: a=> new { FirstName = a.FirstName } );

UPDATE

Since you cannot use already mapped context entities in you queries, due to "The entity or complex type '...' cannot be constructed" error, the best solution I see is to have a separate class with few properties that required for your page. Like:

public class AuthorDetails {
   public string FirstName {get; set;}
}

And then use this class in the query and in the views:

var authors = unitOfWork.AuthorRepository.Get(filter: x => x.TenantID == 1, selector: a=> new AuthorDetails { FirstName = a.FirstName } );

Upvotes: 1

Related Questions