MVC viewmodel and a linq query - linq

I finally (after 4 weeks) got a result for a MVC5 project and it went well.
Now I'm trying to "limit" the number of results and it's flagging an error:
'Stoopid' is a type, which is not valid in the given context
'Student' is a type, which is not valid in the given context
Here's the model:
namespace viewModelA
{
public class Teacher
{
public int TeacherId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
public class Student
{
public int StudentId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string EnrollmentNo { get; set; }
}
public class Stoopid
{
[Key]
public int StoopID { get; set; }
public DateTime stopDt { get; set; }
}
public class ViewModel
{
public IEnumerable<Teacher> Teachers { get; set; }
public IEnumerable<Student> Students { get; set; }
public IEnumerable<Stoopid> Stoopids { get; set; }
}
}
and this is the linq query - notice that Teacher is fine, but Student and Stoopid are NOT. And they are all in the same .cs file. Am I missing something?
var result = (from t in Teacher
join s in Student on t.TeacherId equals s.StudentId
join st in Stoopid on s.StudentId equals st.StoopID
where t.TeacherId == 2
select new
{
TeacherID= t.TeacherId,
Code = t.Code,
t.Name,
s.StudentId,
sCode =s.Code,
sName=s.Name,
stopDt= st.stopDt
})
Edit: I added the relevant code to the HomeController. I also ran this thru LINQPad5 and it works fine so I don't know what's the deal
HomeController

You're referencing the class names in your Linq query, which is why it is throwing that error. You need to reference the actual List objects instead.
var result = (from t in mymodel.Teachers
join s in mymodel.Students on t.TeacherId equals s.StudentId
join st in mymodel.Stoopids on s.StudentId equals st.StoopID
where t.TeacherId == 2
select new
{
TeacherID= t.TeacherId,
Code = t.Code,
t.Name,
s.StudentId,
sCode =s.Code,
sName=s.Name,
stopDt= st.stopDt
})

Related

EF Core non-existant column in query, how to rectify?

working my way through an EF core project I have inherited and am quite new when it comes to LINQ/EF core.
I'll cut this back to simplify things, and will demonstrate my problem with 4 basic tables.
Customer
CustomerId
Name
Contact
1
John
john#gmail.com
2
Peter
peter#gmail.com
CustomerTrade
Id
CustomerId
OtherDetail
T1
1
xyz
T2
1
abc
CustomerTradeParameter
ParamID
TradeId
Value
X
1
1234
Y
1
5678
CustomerTradeParameterType
ParamID
Name
OtherGenericInfo
X
Hello
Null
Y
Test
Null
Models
public class Customer : AuditableEntity
{
public long CustomerId { get; private set; }
public string Name { get; private set; }
public string Contact { get; private set; }
public virtual ICollection<CustomerTrade> CustomerTradeList{ get; set; }
protected Customer()
{ }
public class CustomerTrade : AuditableEntity
{
public long Id { get; private set; }
public long CustomerId { get; private set; }
public string OtherDetail { get; private set; }
public virtual ICollection<CustomerTradeParameter> CustomerTradeParameterList { get; set; } = new List<CustomerTradeParameter>();
protected CustomerTrade() // For EF Core
{ }
public class CustomerTradeParameter : AuditableEntity
{
public long TradeId { get; set; }
public string ParameterType { get; private set; }
public string Value{ get; private set; }
protected CustomerTradeParameter() // For EF Core
{ }
}
DTOs
public class CustomerTradeDto : AuditableDto
{
public long Id { get; set; }
public long CustomerId { get; set; }
public virtual ICollection<CustomerTradeParameterDto> CustomerTradeParameterList { get; set; } = new List<CustomerTradeParameterDto>();
}
public class CustomerTradeParameterDto : AuditableDto
{
public long TradeId { get; set; }
public string ParameterType { get; set; }
public string Value { get; set; }
}
The below query is attempting to retrieve a specific trade, and a list of its relevant parameters.
IQueryable<CustomerTradeDto> foundTrade = _database.CustomerTrade
.Select(trade => new CustomerTradeDto
{
Id = trade.Id,
CustomerId = trade.CustomerId,
CustomerTradeParameterList = trade.CustomerTradeParameterList.Select(param => new CustomerTradeParameterDto{
ParameterType = param.ParameterType,
TradeId = customerTrade.Id,
Value = param.Value
// (second question written further below) - If I wanted to additionally retrieve the CustomerTradeParameterType record
// (to get the name of this parameter), how would I embed this join?
// I originally had ParameterType defined as a "CustomerTradeParameterType" instead of a string,
// but am not sure how to add this extra join inside this select?
}).ToList()
})
.Where(e => e.Id == find.Id);
The .Select on CustomerTradeParameterList is raising the following error:
Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid column name 'CustomerTradeId'.
I understand EF core is attempting to define a column that it is unsure of, but I am not sure how to fix this? The correct column is TradeId.
Secondly, I have an additional question regarding joins inside a sub .Select. In the query above I have a comment outlining the question.
Appreciate any tips you can provide!

How to join 3 tables in linq and get some not included fields in query

I'm implementing asp.net core project. I have 3 tables Apiapp, ApiAppHistory and EntityType. There are three fields with the names SentType, Status and Reason in ApiAppHistory and those fields are of kind Id (int type) in APIApphistory. I joined ApiApp and ApiAppHistory tables in order to get those three fields from ApiAppHistory but because they are of kind int and are unclear when showing the result to the user, I join them with EntityType table which has their related name. In the select part of my query, in addition to ApiApp fields I also need to have SentType, Status and Reason value fields.
Here below is my incomplete query:
var qq = _context.Apiapp
.Include(a => a.Api)
.Include(a => a.Application)
.Include(a => a.Data);
var t12 = (from r in qq
from b in _context.ApiAppHistory
from s in _context.EntityType
where r.LastRequest== b.Id && b.SentType == s.Id
&& b.Reason == s.Id
&& b.Status == s.Id
select new { r, s.name for Reason, s.name for
SentType ,s.name for Status});
I want in select part of my query, obtain name of the fields that I specified from the EntityType table. However, I don't know how to do it. I appreciate if someone helps me.
Here is my EntityType table:
Here are my APIAppHistory and EntityType class model:
public partial class ApiAppHistory
{
public int Id { get; set; }
public int? SentType { get; set; }
public int? Reason { get; set; }
public int? Status { get; set; }
public virtual Apiapp ApiApp { get; set; }
public virtual EntityType StatusNavigation { get; set; }
public virtual EntityType SentTypeNavigation { get; set; }
public virtual EntityType ReasonNavigation { get; set; }
}
public partial class EntityType
{
public EntityType()
{
ApiAppHistoryStatusNavigation = new HashSet<ApiAppHistory>();
ApiAppHistorySentTypeNavigation = new HashSet<ApiAppHistory>();
ApiAppHistoryReasonNavigation = new HashSet<ApiAppHistory>();
}
public int Id { get; set; }
public string Name { get; set; }
public string EntityKey { get; set; }
public virtual ICollection<ApiAppHistory> ApiAppHistoryStatusNavigation { get; set; }
public virtual ICollection<ApiAppHistory> ApiAppHistorySentTypeNavigation { get; set; }
public virtual ICollection<ApiAppHistory> ApiAppHistoryReasonNavigation { get; set; }
}
}

c# AutoMapper ProjectTo selects all nested object properties

Let's take such classes:
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public string ExtraProp { get; set; }
}
public class Parent
{
public int Id { get; set; }
public string Text { get; set; }
public Child Child { get; set; }
public string ParentExtraProp { get; set; }
}
public class ChildVo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ParentVo
{
public int Id { get; set; }
public string Text { get; set; }
public ChildVo Child { get; set; }
}
Automapper mapping:
Mapper.CreateMap<Child, ChildVo>();
//.ForSourceMember(x => x.ExtraProp, o => o.Ignore()); //does not help
//.IgnoreAllNonExisting(); //does not help
Mapper.CreateMap<Parent, ParentVo>();
and query in Linq to Nhibernate:
var test = Session.Query<Parent>()
.Where(x => x.Id == myId)
.ProjectTo<ParentVo>()
.ToList();
ProjectTo selects only columns (properties) which are defined in ParentVo (not all properties from Parent class) - that's great. But is selects all columns (properties) from my Child class, despite the fact that they are not defined in ChildVo.
Why does Automapper ignore my nested property mapping? Is it possible to use all defined mappings during projection?
While I'm not familiar with nhibernate, the same test you've performed here works fine in Entity Framework. In EF you can see the query which has been generated before executing it - try doing this and seeing if it shows the additional column.
public class TestContext : DbContext {
public DbSet<Parent> Parents { get; set; }
}
var query = testContext.Parents.ProjectTo<ParentVo>();
Console.WriteLine(query.ToString());
This produces the following output (note no ExtraProp):
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Text] AS [Text],
CASE WHEN ([Extent2].[Id] IS NOT NULL) THEN 1 END AS [C1],
[Extent1].[Child_Id] AS [Child_Id],
[Extent2].[Name] AS [Name]
FROM [dbo].[Parents] AS [Extent1]
LEFT OUTER JOIN [dbo].[Children] AS [Extent2] ON [Extent1].[Child_Id] = [Extent2].[Id]
This makes me think that the problem is not AutoMapper specifically, but without seeing the generated query it's hard to tell.

Performing a join in LINQ using SQL Syntax

I'm currently learning the Entity Framework and am trying to build an enrollment system. Right now I'm trying to display the courses that a student is enrolled in by using an association table called "EnrollmentModel". Normally if this were SQL my query would be something like:
SELECT *
FROM EnrollmentModel as e, StudentModel as s, CourseModel as c
WHERE s.ID = e.StudentID AND e.CourseID = c.ID
So is there a way to just do that using LINQ? Or do I have to 'translate' the syntax from SQL to LINQ (which I have no idea how to do).
My Schema:
public class StudentModel
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<EnrollmentModel> Enrollments {get; set; }
}
public class EnrollmentModel
{
public int ID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual StudentModel Students { get; set; }
public virtual CourseModel Courses { get; set; }
}
public class CourseModel
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<EnrollmentModel> Enrollments { get; set; }
}
If you change the SQL query to explicit join syntax;
SELECT *
FROM EnrollmentModel as e
JOIN StudentModel AS s ON e.StudentID = s.ID
JOIN CourseModel AS c ON e.CourseID = c.ID
...it's quite straight forward to translate to LINQ into an anonymous type;
var result =
from e in db.EnrollmentModel
join s in db.StudentModel on e.StudentID equals s.ID
join c in db.CourseModel on e.CourseID equals c.ID
select new {e,s,c};

EF 4.1 POCO query

I have this POCO and I want to return a list of the users in a particular company.
public class Company
{
public AccreditedCompany()
{
this.Branches = new HashSet<Branch>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), ScaffoldColumn(false)]
public int CompanyId { get; set; }
public bool Active { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
}
public class Branch
{
public Branch()
{
this.Users = new HashSet<User>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), ScaffoldColumn(false)]
public int BranchId { get; set; }
public int CompanyId { get; set; }
public string Name { get; set; }
public string ContactName { get; set; }
public virtual Company Company { get; set;}
public virtual ICollection<User> Users { get; set; }
}
public class User
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), ScaffoldColumn(false)]
public int UserId { get; set; }
public int BranchId { get; set; }
public string ComputerSN { get; set; }
public string CameraSN { get; set; }
public virtual Branch Branch { get; set; }
}
This is my LINQ query:
var company = (from u in objDataContext.Companies.Include(c=>c.Branches.Select(v=>v.Users))
where u.CompanyId == 8 select u).FirstOrDefault();
IQueryable<User> users = (from j in company.Branches select j.Users);
I have this compilation error on the second query:
Error 2 Cannot implicitly convert type
'System.Collections.Generic.IEnumerable>'
to 'System.Linq.IQueryable'. An explicit conversion exists (are
you missing a cast?)
I want to get a list of the users, similar to a plain SQL statement like
SELECT dbo.Users.* FROM Branches
INNER JOIN dbo.Users ON dbo.Branches.BranchId = dbo.Users.BranchId
INNER JOIN dbo.Companies ON dbo.Branches.CompanyId = dbo.Companies.CompanyId
WHERE (dbo.Companies.CompanyId = 8)
Thanks in advance.
Your user query could be:
IEnumerable<User> users = company.Branches.SelectMany(branch => branch.Users);
This will return all users in any branch of the company.
It looks to me like you could just use:
IQueryable<User> users = objDataContext.Users
.Where(u => u.Branch.CompanyId == 8);
I notice you have both Company and CompanyId on your Branch entity, though. That seems redundant, even though it simplifies this query slightly. You should be able to get rid of Branch.CompanyId and User.BranchId and just use the entity associations.

Resources