Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert Linq results to DTO class object without iteration

I'm building a Web API project that will be made available to third-party's and also used by my own web application/s. The Web API methods will return JSON representations of complex types/objects. These are pre-defined classes which I can make available to third-party's so they understand how the data is structured and can deserialize the JSON. I'll refer to these classes as DTO classes until someone corrects me.

I have the following auto-generated entity model (from database) well this is the User class anyway with a relationship to the Scan table (relationship can be ignored for the purpose of this question)...

public partial class User
{
    public User()
    {
        this.Scans = new HashSet<Scan>();
    }

    public int Id { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public bool Active { get; set; }

    public virtual ICollection<Scan> Scans { get; set; }
}

And the following DTO class which I would like to return to the presentation layer as List (I don't think I should use IEnumerable for business to presentation?).

public class User
{
    public int Id;
    public string Username;
    public string Password;
    public bool Active;
}

My business layer for this component currently looks like below. Using Linq to get users from the database and then parsing the results and returning a List<> of POCO Users.

public List<User> Get()
{
    List<User> userList = new List<User>();

    using (var db = new MyContext())
    {
        var query = from u in db.Users
                    orderby u.FirstName
                    select u;

        foreach (var item in query)
        {
            User user = new User();
            user.Id = item.pkUser;
            user.Username = item.Username;
            user.Password = item.Password;
            user.Active = item.Active;

            userList.Add(user);
        }
    }

    return userList;
}

Parsing through the results like this seems inefficient, and I have seen that you can do this sort of thing in the Linq query without iteration (e.g. the answer in this question Mapping Linq Query results to a DTO class).

I'm unsure as to where/how I should implement IEnumerable to enable this type of Linq query on my objects, and am also unsure of how to write a query similar to the one in the referenced question above but for my much simpler scenario.

Thanks in advance for any help.

P.S. Please ignore the fact that I am exposing Username and Password via Web API and also that I am returning all Users at once. Above is a simplified version of my code for the purpose of this question.

like image 839
Dan Avatar asked Feb 27 '13 23:02

Dan


3 Answers

The complete method could be:

public List<User> Get()
{
    using (var db = new MyContext())
    {
        return (from u in db.Users
                orderby u.FirstName
                select new User()
                {
                    Id = u.pkUser,
                    Username = u.Username,
                    Password = u.Password,
                    Active = u.Active
                }).ToList();
    }
}

You said you want the result "without iteration". Using LINQ also does not eliminate the iteration. You are not doing it in your code, but it really happens when you call the ToList() method.

like image 123
Mohammad Dehghan Avatar answered Oct 02 '22 03:10

Mohammad Dehghan


You can use LINQ to Objects to do the conversion:

using (var db = new MyContext())
{
    var query = from u in db.Users
                orderby u.FirstName
                select u;

    return query.AsEnumerable().Select(item => 
                 new User 
                     { 
                        Id = item.pkUser,
                        Username = item.Username,
                        Password = item.Password,
                        Active = item.Active
                     }).ToList();
}
like image 32
Reed Copsey Avatar answered Oct 04 '22 03:10

Reed Copsey


We can get really compact if we use AutoMapper.

Bootstrap the mapper in your repository:

Mapper.CreateMap<AutoGenNamespace.User, DtoNamespace.User>();

Then it's pretty simple (and there's nothing wrong with returning IEnumerable).

public IEnumerable<User> Get()
{
    using (var db = new MyContext())
    {
        return (from u in db.Users
                orderby u.FirstName
                select Mapper.Map(u)).AsEnumerable();
    }
}
like image 42
Dustin Kingen Avatar answered Oct 01 '22 03:10

Dustin Kingen