LINQ: Why am I getting error on this LINQ Query? - asp.net-mvc

This my method in my repository:
public List<Question> getallquestion()
{
var hej = from Core in db.CoreValue
join Question in db.Question on Core.CID equals question.QID
join Subject in db.SubjectType on Core.CID equals Subject.SID
select new
{
Core.Cname,
Question.QuestionText,
Subject.Sname
};
return hej.ToList();
}
This is the error:
Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'NKI3.Models.Question'
What is the solution for this error? I cant seem to find it
My CreateViewModel:
public class CreateViewModel
{
public string QuestionText { get; set; }
public string Sname { get; set; }
public string Cname {get;set;}
}
}
Thanks in Advance!
Best Regards!

Your linq query produces List of anonymous object (as you use select new { (...) } without any type). You should replace it with select new Question() { (...) }. You should check that select syntax depending on Question class properties.
eg. When you have Name, Text and Subject property is should look like this:
var hej = from c in db.CoreValue
join q in db.Question on c.CID equals q.QID
join s in db.SubjectType on c.CID equals s.SID
select new Question
{
QID = q.QID,
QuestionText = q.QuestionText
};

Change your select to read like so:
public List<CreateViewModel> GetAllQuestionViewModel()
{
var hej = from Core in db.CoreValue
join Question in db.Question on Core.CID equals question.QID
join Subject in db.SubjectType on Core.CID equals Subject.SID
select new CreateViewModel
{
Cname = Core.Cname,
QuestionText = Question.QuestionText,
Sname = Subject.Sname
};
return hej.ToList();
}
In your controller you would do something like this:
public ActionResult Index() {
IEnumerable<CreateViewModel> questions = someContext.GetAllQuestionViewModel();
return View(questions);
}

Your method is expecting to return a collection of your Question type, but your LINQ query is returning a sequence of an anonymous type. You should change your query, for example changing your projection:
public List<Question> getallquestion()
{
var hej = from Core in db.CoreValue
join Question in db.Question on Core.CID equals question.QID
join Subject in db.SubjectType on Core.CID equals Subject.SID
select new Question
{
Name = Core.Cname,
Text = Question.QuestionText,
Subject = Subject.Sname
};
return hej.ToList();
}
This is using an object initializer to assign the property values of the Question type from the result of the query. Your property names will differ.

You can't return an anonymous type.
Create a class
public class QuestionResult
{
public string Core {get; set;}
public string Question {get; set;}
public string Subject{get; set;}
}
and use it
public List<QuestionResult> getallquestion()
{
var hej = from Core in db.CoreValue
join Question in db.Question on Core.CID equals question.QID
join Subject in db.SubjectType on Core.CID equals Subject.SID
select new QuestionResult
{
Core = Core.Cname,
Question = Question.QuestionText,
Subject = Subject.Sname
};
return hej.ToList();
}

Related

problem Viewmodel and LINQ query in asp.net mvc

I am developing an application in asp.net MVC, and for show multi-table in the same view, I have created one big ViewModel which contains the three models (employee, user, and request)
now my problem is my query that not work, and I can't locate the problem
Thank you for your help
Sorry for my english is not good
My bigviewmodel
namespace freegest.Models
{
public class ControleViewModel
{
public List<employe> employes { get; set; }
public List<demande > demandes { get; set; }
public List<utilisateur> utilisateurs { get; set; }
}
}
My query
public ActionResult listdemande()
{
int id = Convert.ToInt32(Session["id_utilisateur"]);
ControleViewModel CV = new ControleViewModel();
CV = (from a in CV.utilisateurs
join b in CV.demandes
on a.id_utilisateur equals b.idutilisateur_demande
join c in CV.employes
on a.idemploye_utilisateur equals c.id_employe
orderby c.nom_employe ascending
where a.id_utilisateur == id
select new ControleViewModel
{
c.nom_employe ,
});
return View(CV);
}
Try the following approach to join multiple tables using LINQ:
public ActionResult Index()
{
using (DBEntities db=new DBEntities())
{
List<Employee> employees = db.Employees.ToList();
List<Department> departments = db.Departments.ToList();
List<Incentive> incentives = db.Incentives.ToList();
var employeeRecord = from e in employees
join d in departments on e.Department_Id equals d.DepartmentId into table1
from d in table1.ToList()
join i in incentives on e.Incentive_Id equals i.IncentiveId into table2
from i in table2.ToList()
select new ViewModel
{
employee=e,
department=d,
incentive=i
};
return View(employeeRecord);
}
}

How to create a simple left outer join in lambda expression in EF ASP.NET MVC5

I searched hours and hours for this without any luck. I'm trying to create a lambda expression to fetch data from two tables Schedule and Request. But i'm outputting a bool here. How can i do a proper left outer join to fix this?
this is the best i could come up with
ViewBag.RequestList = db.Requests
.Include(r => r.Department)
.Select(r => db.Schedules.Any(s => s.RequestId == r.RequestId));
but its a bool not a list.
Assume my table models are as follows
public class Request{
public virtual int RequestId { get; set; }
public virtual string Remarks { get; set; }
}
public class Schedule{
public virtual int ScheduleId{ get; set; }
public virtual string Name{ get; set; }
public virtual Request Request { get; set; }
}
I'm trying to see if each and every request has one or more schedules associated with it or not. so if i could attach schedule object to request and output it as a list then thats all i need.
But I want to do it using LINQ and lambda expressions and I've seen queries as below;
var leftList = (from emp in db.Requests
join d in db.Schedules
on emp.RequestId equals d.RequestId into output
from j in output.DefaultIfEmpty()
select new { RequestId = emp.RequestId,
name = emp.Department.Name,
route = emp.Route.Name });
But that's not what i want, because i have to specify every field i need in new { RequestId = emp.RequestId, name = emp.Department.Name, route = emp.Route.Name }
Thanks a lot!
just list what you want like this:
var leftList = from emp in db.Requests
join d in db.Schedules
on emp.RequestId equals d.RequestId into output
from j in output.DefaultIfEmpty()
select new
{
RequestId = emp.RequestId,
name = emp.Department.Name,
route = emp.Route.Name,
ScheduleId=j==null?0:j.ScheduleId,
SName=j==null?""j.Name,
};

MVC Kendo dropdown read/get items with join between a table and view

I'm trying to populate a Kendo dropdown using a Read function in a controller, but do so in a way that allows me to get items from one table or a view, based on a column in the view.
Ex.
public class AlternateCountry // <-- Table
{
public Guid CountryGUID { get; set; }
public string Name { get; set; }
}
public class Countries // <-- View
{
public bool hasAltName { get; set; }
public Guid GUID { get; set; }
public string Name { get; set; }
}
I want to show the "Countries" Name column value unless we have an alternate name for that country. Then it would show the Name column in the "AlternateCountry" table. Something like:
var getCountries = (from c in db.Countries
join alt in db.AlternateCountry on c.GUID equals alt.CountryGUID
where c.hasAltName == true
select new {
GUID = c.GUID,
Name = alt.Name
}).ToList();
return Json(getCountries, JsonRequestBehavior.AllowGet);
Problem is this doesn't account for when the alternate name is false, to grab "Name" from the Countries view. I can duplicate another of these blocks and change c.hasAltName == false, but how do I then combine both of these into one DataSourceResult set?
Actually, I was able to solve this with a union of two queries -- one for the ones without alternate names, one for those with alternate names:
var realCountries = (from c in db.Countries
where c.hasAltName == false
select new {
GUID = c.GUID,
Name = c.Name
}).ToList();
var fakeCountries = (from c in db.Countries
join alt in db.AlternateCountry on c.GUID equals alt.CountryGUID
where c.hasAltName == true
select new {
GUID = alt.GUID,
Name = alt.Name
}).ToList();
var allCountries = realCountries.Union(fakeCountries);
return Json(allCountries, JsonRequestBehavior.AllowGet);

LINQ to Entities does not recognize the method. Guid causing trouble?

In my model class OwnedModule i have OwnerID as Guid.
There is another model class called BusinessUnit which contains the same Guid value from OwnedModule and its OwnerName.
I want to show the details of OwnedModule, which contains all the details about the hardware but has the owner as Guid value and not the name, and for this i have created a view model
public class OwnedModuleViewModel
{
public long Id { get; set; }
public string ModuleId { get; set; }
public string TypeName { get; set; }
public string KindName { get; set; }
public string Owner { get; set; }
public DateTime OwnershipStart { get; set; }
}
public class IndexOwnedModule
{
public List<OwnedModuleViewModel> OwnedModules { get; set; }
}
to show all this detail in my repository i have following function
public IndexOwnedModule GetAllOwnedModules()
{
var modulesList = new IndexOwnedModule();
var modules = (_dbSis.OwnedModules.OrderBy(module => module.Id).Select(module => new OwnedModuleViewModel
{
Id = module.Id,
ModuleId = module.ModuleId,
TypeName = module.ModuleType.TypeName,
Owner = GetModuleOwner(module.ModuleOwnerId),//error here
OwnershipStart = module.Start
}));
modulesList.OwnedModules = modules.ToList();
return modulesList;
}
public string GetModuleOwner(Guid id)
{
var ownedModule =_dbSis.Set<BusinessUnit>().FirstOrDefault(t => t.Id == id);
if (ownedModule != null) return ownedModule.Name;
return null;
}
It would not be convinient to show the guid value as owner in the view to user so I wanted to fetch the name for which I had GetModuleOwnerName.
But it seems like the way i've set the name of the owner to my viewmodel view is wrong, and when i run the application i get the following error.
LINQ to Entities does not recognize the method 'System.String GetModuleOwner(System.Guid)' method, and this method cannot be translated into a store expression.
When i comment the line where I've set the value of owner(Owner = GetModuleOwner(module.ModuleOwnerId)), everything works fine.
When Entity Framework build your query, it relies on the inspection of the passed Expression Tree. When it encounter a method call, it will try to map it to an equivalent SQL method using (see this for the canonical methods). Because Entity Framework has no knowledge of OwnedModuleViewModel.GetModuleOwner, it cannot generate an appropriate SQL query. In this case, the simple way would be to embed what your method does in the query instead of calling a method:
_dbSis.OwnedModules
.OrderBy(module => module.Id)
.Select(module => new OwnedModuleViewModel
{
Id = module.Id,
ModuleId = module.ModuleId,
TypeName = module.ModuleType.TypeName,
Owner = _dbSis.Set<BusinessUnit>()
.Where(t => t.Id == module.ModuleOwnerId)
.Select(t => t.Name).FirstOrDefault(),
OwnershipStart = module.Start
});
Of course, that is assuming _dbSis.Set<BusinessUnit>() is a DbSet<T> part of the same DbContext, otherwise the same problem arise.
In Linq-To-Entities, a Linq statement against a context gets translated to a SQL statement. It's obviously impossible to translate the GetModuleOwner() method to SQL. You need to get the ModuleOwnerId first, and then in another step after, call GetModuleOwner() on each ModuleOwnerId.
Or you could restructure your query to use a join:
var modules = from m in _dbSis.OwnedModules
join b in _dbSis.BusinessUnit on m.ModuleOwnerId equals b.Id
order by m.Id
select new OwnedModuleViewModel {
Id = m.Id,
ModuleId = m.ModuleId,
TypeName = m.ModuleType.TypeName,
Owner = b.Name,
OwnershipStart = m.Start};
modulesList.OwnedModules = modules.ToList();
NOTE: I didn't test this so it might have some minor syntax errors.
This could be another option
var ownedModules = _dbSis.OwnedModules.OrderBy(module => module.Id).Select(module => new
{
Id = module.Id,
ModuleId = module.ModuleId,
TypeName = module.ModuleType.TypeName,
ModuleOwnerId = module.ModuleOwnerId,
OwnershipStart = module.Start
}).ToList().Select(m => new OwnedModuleViewModel
{
Id = m.Id,
ModuleId = m.ModuleId,
TypeName = m.TypeName,
Owner = GetModuleOwner(m.ModuleOwnerId),
OwnershipStart = m.OwnershipStart
});
ownedModulesList.OwnedModules = ownedModules.ToList();
return ownedModulesList;

Retrieving data from a one-to-many relationship

I'm trying to retrieve data from a one-to-many relationship, in an ASP.NET MVC application.
Let's say I have two tables Posts and Category with the following attributes:
posts
-id
-title
-category_id
category
-id
-name
-author
I want to grab posts that belong to a category and grab the values of .name and .author from the category.
This is what I have in the model:
public IQueryable<Post> GetPosts()
{
return from post in db.Posts
join categories in FindCategories()
on categories.id equals post.category_id
select new
{
title = post.title,
name = categories.name,
author = categories.author
};
}
And in the controller:
public ActionResult Index()
{
var allposts = postRepository.GetPosts().ToList();
return View(allposts);
}
The model complaints that it can't convert and IQueryable of Anonymous type into an IQueryable < Post >. I suspect it's because I'm doing Select new { }, but I'm not sure.
If I do IQueryable only then I don't have the ToList() method available in the view.
So, I'm lost. Can you help?
(an by the way, I'm a complete newbie at this asp.net mvc thing.)
I think the problem is that you're trying to use a var outside of the scope of a single method. In your projection stage try newing-up a Post object rather than an anonymous type. e.g.
public IQueryable<Post> GetPosts()
{
return from post in db.Posts
join categories in FindCategories()
on categories.id equals post.category_id
select new Post()
{
title = post.title,
name = categories.name,
author = categories.author
};
}
The question has been answered by Lazarus in the comments. Your method declaration states a return type of IQueryable of Post types
public IQueryable<Post> GetPosts() { //...
But your linq projects to an anonymous type and returns an IQueryable of anonymous types
select new { //anonymous type
title = post.title,
name = categories.name,
author = categories.author
}; // = IQueryable<SomeCompilerGeneratedTypeNameHere>
You need to define a new type
public class PostDisplay {
public string Title { get; set; }
public string Name { get; set; }
public string Author { get; set; }
}
then in your code return an IQueryable of that type
public IQueryable<PostDisplay> GetPosts() {
return from post in db.Posts
join categories in FindCategories()
on categories.id equals post.category_id
select new PostDisplay {
Title = post.title,
Name = categories.name,
Author = categories.author
};
}

Resources