What is Func<> ?

Func<> is a shorthand for a delegate that takes 0 or more parameters and returns a result. We can assign a Func<> type by providing a lambda expression.

Func<T, TResult> delegate, they are defined separately for each number of parameters from 0 to 17.
  1. public delegate TResult Func<in T, out TResult>(T arg)
What is params?

Parameters are just syntactic sugar. Ultimately, the parameter is just an array. Therefore, the parameter type should be object[] and an expression describing such an array is what you should pass as the second argument.
Here is one simple example of addition of two numbers.
  1. Expression<Func<int, int, int>> expression = (A, B) => A + B;
  2. Func<int, int, int> compiledExpression = expression.Compile();
  3. int result = compiledExpression(3, 4);
  4. Console.WriteLine("Addition is {0}",result); // output 7
  5. Console.ReadLine();
Step 1 Create new MVC Empty project in Visual Studio

Create database with three different tables. Use first table to store user login information; second table to store user details like address and phone number etc.; and third table to store the information of the technology on which the user is currently working.

All three tables having a primary key & foreign key relationship.

Below is the table script which has some dummy data.
  1. USE [Company]
  2. GO
  3. SET ANSI_NULLS ON
  4. GO
  5. SET QUOTED_IDENTIFIER ON
  6. GO
  7. SET ANSI_PADDING ON
  8. GO
  9. CREATE TABLE [dbo].[LoginInfo](
  10. [Id] [int] IDENTITY(1,1) NOT NULL,
  11. [FirstName] [varchar](50) NULL,
  12. [UserName] [varchar](50) NULL,
  13. [Password] [varchar](50) NULL,
  14. CONSTRAINT [PK_LoginInfo] PRIMARY KEY CLUSTERED
  15. (
  16. [Id] ASC
  17. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  18. ) ON [PRIMARY]
  19. GO
  20. SET ANSI_PADDING OFF
  21. GO
  22. SET ANSI_NULLS ON
  23. GO
  24. SET QUOTED_IDENTIFIER ON
  25. GO
  26. SET ANSI_PADDING ON
  27. GO
  28. CREATE TABLE [dbo].[UserDetails](
  29. [Id] [int] IDENTITY(1,1) NOT NULL,
  30. [UserId] [int] NOT NULL,
  31. [Address] [varchar](50) NULL,
  32. CONSTRAINT [PK_UserDetails] PRIMARY KEY CLUSTERED
  33. (
  34. [Id] ASC
  35. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  36. ) ON [PRIMARY]
  37. GO
  38. SET ANSI_PADDING OFF
  39. GO
  40. SET ANSI_NULLS ON
  41. GO
  42. SET QUOTED_IDENTIFIER ON
  43. GO
  44. SET ANSI_PADDING ON
  45. GO
  46. CREATE TABLE [dbo].[UserPost](
  47. [Id] [int] IDENTITY(1,1) NOT NULL,
  48. [UserId] [int] NOT NULL,
  49. [PostDetails] [varchar](50) NULL,
  50. CONSTRAINT [PK_UserPost] PRIMARY KEY CLUSTERED
  51. (
  52. [Id] ASC
  53. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  54. ) ON [PRIMARY]
  55. GO
  56. SET ANSI_PADDING OFF
  57. GO
  58. SET IDENTITY_INSERT [dbo].[LoginInfo] ON
  59. GO
  60. INSERT [dbo].[LoginInfo] ([Id], [FirstName], [UserName], [Password]) VALUES (1, N'Rupesh', N'rupesh', N'123')
  61. GO
  62. INSERT [dbo].[LoginInfo] ([Id], [FirstName], [UserName], [Password]) VALUES (2, N'Ajit', N'ajit', N'123')
  63. GO
  64. SET IDENTITY_INSERT [dbo].[LoginInfo] OFF
  65. GO
  66. SET IDENTITY_INSERT [dbo].[UserDetails] ON
  67. GO
  68. INSERT [dbo].[UserDetails] ([Id], [UserId], [Address]) VALUES (1, 1, N'Baner')
  69. GO
  70. INSERT [dbo].[UserDetails] ([Id], [UserId], [Address]) VALUES (2, 2, N'Viman Nagar')
  71. GO
  72. SET IDENTITY_INSERT [dbo].[UserDetails] OFF
  73. GO
  74. SET IDENTITY_INSERT [dbo].[UserPost] ON
  75. GO
  76. INSERT [dbo].[UserPost] ([Id], [UserId], [PostDetails]) VALUES (1, 1, N'MVC')
  77. GO
  78. INSERT [dbo].[UserPost] ([Id], [UserId], [PostDetails]) VALUES (2, 2, N'Node Js')
  79. GO
  80. SET IDENTITY_INSERT [dbo].[UserPost] OFF
  81. GO
  82. ALTER TABLE [dbo].[UserDetails] WITH CHECK ADD CONSTRAINT [FK_Login] FOREIGN KEY([UserId])
  83. REFERENCES [dbo].[LoginInfo] ([Id])
  84. GO
  85. ALTER TABLE [dbo].[UserDetails] CHECK CONSTRAINT [FK_Login]
  86. GO
  87. ALTER TABLE [dbo].[UserPost] WITH CHECK ADD CONSTRAINT [FK_LoginInfo] FOREIGN KEY([UserId])
  88. REFERENCES [dbo].[LoginInfo] ([Id])
  89. GO
  90. ALTER TABLE [dbo].[UserPost] CHECK CONSTRAINT [FK_LoginInfo]
  91. GO
Step 2

Now, I have added two class libraries in the project - one for Infrastructure & another one for Repository pattern. In Infrastructure class library, I have added .EDMX file generated from database. In Repository class library, I have created Unit of Work & Repository Pattern.
Below code is used for Generic Repository class.
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data.Entity;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using Infrastructure;
  9. using System.Data;
  10. namespace Repository
  11. {
  12. public class GenericRepository<T> : IGenericRepository<T> where T : class
  13. {
  14. internal DbContext context;
  15. internal DbSet<T> dbSet;
  16. public GenericRepository(DbContext context)
  17. {
  18. this.context = context;
  19. this.dbSet = context.Set<T>();
  20. }
  21. public void Save()
  22. {
  23. throw new NotImplementedException();
  24. }
  25. public virtual IEnumerable<T> GetWithRawSql(string query, params object[] parameters)
  26. {
  27. throw new NotImplementedException();
  28. }
  29. public virtual IEnumerable<T> GetAll(
  30. Expression<Func<T, bool>> filter = null,
  31. Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
  32. params Expression<Func<T, object>>[] navigationPropeties)
  33. {
  34. throw new NotImplementedException();
  35. }
  36. public virtual IEnumerable<T> GetAllExpressions(
  37. Expression<Func<T, bool>> filter = null,
  38. Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
  39. params Expression<Func<T, object>>[] naProperties)
  40. {
  41. IQueryable<T> dbQuery = dbSet;
  42. if (filter != null)
  43. {
  44. dbQuery = dbQuery.Where(filter);
  45. }
  46. foreach (Expression<Func<T, object>> nProperty in naProperties)
  47. dbQuery = dbQuery.Include<T, object>(nProperty);
  48. if (orderBy != null)
  49. {
  50. dbQuery = orderBy(dbQuery);
  51. }
  52. return dbQuery.ToList();
  53. }
  54. public virtual T GetByID(object id)
  55. {
  56. throw new NotImplementedException();
  57. }
  58. public virtual void Insert(T entity)
  59. {
  60. throw new NotImplementedException();
  61. }
  62. public virtual void Delete(object id)
  63. {
  64. throw new NotImplementedException();
  65. }
  66. public virtual void Delete(T entityToDelete)
  67. {
  68. throw new NotImplementedException();
  69. }
  70. public virtual void Update(T entityToUpdate)
  71. {
  72. throw new NotImplementedException();
  73. }
  74. public virtual T GetSingle(Expression<Func<T, bool>> where,
  75. params Expression<Func<T, object>>[] navigationProperties)
  76. {
  77. throw new NotImplementedException();
  78. }
  79. private IQueryable<T> orderBy(IQueryable<T> dbQuery)
  80. {
  81. throw new NotImplementedException();
  82. }
  83. }
  84. }
The following code is used for IGeneric Repository class.
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using System.Data;
  9. using System.Data.Entity;
  10. namespace Repository
  11. {
  12. public interface IGenericRepository<T> where T : class
  13. {
  14. IEnumerable<T> GetAll(Expression<Func<T, bool>> filter = null,
  15. Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
  16. params Expression<Func<T, object>>[] navigationPropeties);
  17. IEnumerable<T> GetAllExpressions(
  18. Expression<Func<T, bool>> filter = null,
  19. Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
  20. params Expression<Func<T, object>>[] naProperties);
  21. IEnumerable<T> GetWithRawSql(string query, params object[] parameters);
  22. T GetByID(object id);
  23. void Insert(T entity);
  24. void Delete(object id);
  25. void Delete(T entityToDelete);
  26. void Update(T entityToUpdate);
  27. void Save();
  28. }
  29. }
The below code is for Unit of Work Pattern.
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Infrastructure;
  7. namespace Repository
  8. {
  9. public class UnitOfWork : IDisposable
  10. {
  11. private CompanyEntities context = new CompanyEntities();
  12. private IGenericRepository<LoginInfo> loginRepository;
  13. private IGenericRepository<UserDetail> userDetailsRepository;
  14. private IGenericRepository<UserPost> userPostRepository;
  15. public IGenericRepository<LoginInfo> LoginRepository
  16. {
  17. get
  18. {
  19. return loginRepository ?? (loginRepository = new GenericRepository<LoginInfo>(context));
  20. }
  21. }
  22. public IGenericRepository<UserDetail> UserDetailsRepository
  23. {
  24. get
  25. {
  26. return userDetailsRepository ?? (userDetailsRepository = new GenericRepository<UserDetail>(context));
  27. }
  28. }
  29. public IGenericRepository<UserPost> UserPostRepository
  30. {
  31. get
  32. {
  33. return userPostRepository ?? (userPostRepository = new GenericRepository<UserPost>(context));
  34. }
  35. }
  36. private bool disposed = false;
  37. protected virtual void Dispose(bool disposing)
  38. {
  39. if (!this.disposed)
  40. {
  41. if (disposing)
  42. {
  43. context.Dispose();
  44. }
  45. }
  46. this.disposed = true;
  47. }
  48. public void Dispose()
  49. {
  50. Dispose(true);
  51. GC.SuppressFinalize(this);
  52. }
  53. }
  54. }
Step 3

Now, create one folder, ViewModel, in your project. Add HomeViewModel and some properties into that. I would like to display First Name, Address, Technology on View, so I am going to add these properties as below.
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using Infrastructure;
  6. namespace Core.ViewModel
  7. {
  8. public class HomeViewModel
  9. {
  10. public HomeViewModel(UserPost objUserPost)
  11. {
  12. FirstName = objUserPost.LoginInfo.FirstName;
  13. Address = objUserPost.LoginInfo.UserDetails.FirstOrDefault().Address;
  14. PostDetails = objUserPost.PostDetails;
  15. }
  16. public string FirstName { get; set; }
  17. public string Address { get; set; }
  18. public string PostDetails { get; set; }
  19. }
  20. }
Step 4

Now, create Base Controller to access the global object of Unit Of Work by declaring constructor.
  1. using Repository;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Web;
  6. using System.Web.Mvc;
  7. namespace Core.Controllers
  8. {
  9. public class BaseController : Controller
  10. {
  11. protected UnitOfWork UnitoffWork { get; private set; }
  12. public BaseController()
  13. {
  14. UnitoffWork = new UnitOfWork();
  15. }
  16. }
  17. }
Step 5

Now, add HomeController. In Action method by declaring Expression, we can get information from multiple tables into a single variable.

Note - As we have a relationship in between these three tables, we will get records based on that relationship.
  1. using Infrastructure;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Web;
  7. using System.Web.Mvc;
  8. namespace Core.Controllers
  9. {
  10. public class HomeController : BaseController
  11. {
  12. public ActionResult Index()
  13. {
  14. Expression<Func<UserPost, object>> parameter1 = v => v.LoginInfo;
  15. Expression<Func<UserPost, object>> parameter2 = v => v.LoginInfo.UserDetails;
  16. Expression<Func<UserPost, object>>[] parameterArray = new Expression<Func<UserPost, object>>[] { parameter1, parameter2 };
  17. var userPost = UnitoffWork.UserPostRepository.GetAllExpressions(naProperties: parameterArray).Select(u => new HomeViewModel(u)).ToList();
  18. return View(userPost);
  19. }
  20. }
  21. }
Step 6

Now, create View against above action method.
  1. @model IEnumerable<Core.ViewModel.HomeViewModel>
  2. @{
  3. Layout = null;
  4. }
  5. <!DOCTYPE html>
  6. <html>
  7. <head>
  8. <meta name="viewport" content="width=device-width" />
  9. <title>Parameter Array</title>
  10. </head>
  11. <body style="margin-left:50px">
  12. <h2>
  13. Get data from mutliple tables using parameters when combining linq expressions
  14. </h2>
  15. @foreach (var item in Model)
  16. {
  17. <br />
  18. <span style="color:red"> @Html.Label("Name") :</span> @Html.Label(item.FirstName.ToString())
  19. <br />
  20. <span style="color:red"> @Html.Label("Address") :</span> @Html.Label(item.Address.ToString())
  21. <br />
  22. <span style="color:red"> @Html.Label("Working On") :</span> @Html.Label(item.PostDetails.ToString())
  23. <br />
  24. }
  25. </body>
  26. </html>
Step 7

Now, run the application and you will see the result.

Summary

In this article, you learned the basics of how to get data from multiple tables using parameters when combining LINQ Expressions, using repository pattern.