c#. EF entity sql. How to get entity with related objects? - c#

I have made simple model for example.
public class Publisher
{
public int Id { get; set; }
public string Title { get; set; }
public Address Location { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Address
{
public string Country { get; set; }
public string City { get; set; }
public string Street { get; set; }
public string HouseNumber { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public int LanguageId { get; set; }
public int? PublisherId { get; set; }
}
I need to get publishers with related books. I know how to do it using linq to entities. Is it possible to solve a problem using entity sql?
public class CatalogContext : DbContext {...}
public List<Publisher> GetByCity(string city)
{
var result = new List<Publisher>();
string queryString;
queryString = String.Format(#"SELECT VALUE row(a,b)
FROM CatalogContext.Publishers AS a
join CatalogContext.Books AS b on a.Id = b.PublisherId
WHERE a.Location.City = '{0}'", city);
var rows = ((IObjectContextAdapter)_context).ObjectContext.CreateQuery<DbDataRecord>(queryString).ToList();
return ???
}
Query returns required data but it's List<DbDataRecord> - list of pairs <publisher, book>. How to translate it to list of publishers with filled navigation property "Books"?
Is it possible to write query which directly returns List<Publisher>?

you can do the following:
var result = ObjectContext.Publishers.Include("Books").Include("Locations")
.Where(c => c.Location.City = "SOME_CITY").Select(c => c);
Include - basically joins the table.
Then you can drill down to books by doing the following:
var test = result[0].Books;
Why are you using direct sql command instead of Entity Framework code style?

Related

How to order by with related entity properties in EF core

Hello I want to sort my end result using related entity property which is in this case Locality. I got the keyword from client end as a string that includes column name and sort direction eg. "locality=asc" but when I do orderby with any parent entity properties it run fine however, the property with related entity gives me an error by saying that customer object does not have any locality property
here is my both class customer and Address
public class Customer : IEntity
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public Guid UserId { get; set; }
public DateTime DateCreated { get; set; }
public DateTime LastUpdated { get; set; }
[ForeignKey("Address")]
public Guid AddressId { get; set; }
public virtual Address Address { get; set; }
}
public class Address: IEntity
{
public Guid Id { get; set; }
public string Lat { get; set; }
public string Lon { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Locality { get; set; }
}
Here I am trying to sort it with Address property like locality
int skip = (pageNum - 1) * pageSize;
if (skip < 0)
{
skip = 0;
}
searchTerm = searchTerm.ToLower();
var query = _context.Customers.Include(q => q.Address)
.Where(c => c.FirstName.ToLower().Contains(searchTerm)
|| c.LastName.ToLower().Contains(searchTerm)
|| c.Email.ToLower().Contains(searchTerm)
|| c.Mobile.ToLower().Contains(searchTerm));
//var sortOrderSplit = sortOrder.Split('=');
if (sortOrderSplit[0].ToLower() != "locality")
{
query = query.OrderByField("Email", "asc");
}
{
query = query.OrderByField("locality", "asc"); //that gives me an error because type is Address not Customer
}
var customers = query
.Skip(skip)
.Take(pageSize)
.ToList();
u want order by Locality ASC,right?
I think Class type of query is IEnumerable,so you can use lumbda expression.
because Locality is in Address Class,should follow the flow Customer => Address => Locality,not only search property Locality.
if (sortOrderSplit[0].ToLower() != "locality")
{
query = query.OrderBy(o => o.Email);
}
else
{
query = query.OrderBy(o => o.Address.Locality);
}
If your two entity classes have One-to-One relationship, you must add
public Customer Customer { get; set; }
into your Address class too.
Do this and try again.

How to name the intermediate entity lists in a LINQ query?

I need help with a specific LINQ query. I couldn't find a way to group intermediate entities and use them in my select statement.
The domain: We have a list of criteria Questions to assess Projects. There are Assessors that assess the projects and give them QuestionScores which include notes. When an assessor is assessing a project, they should be able to see other assessor's notes. Assessors also are able to reassess, then they also see their previous note.
I wrote the following query for this that will return a list of QuestionModels, however, I don't know how to fill some of the parts.
string assessorId = "assessor_id_0";
string projectId = "project_id_0";
var query =
from question in _context.Questions
join questionScore in _context.QuestionScores on question.Id equals questionScore.QuestionId
join assessment in _context.Assessments on questionScore.AssessmentId equals assessment.Id
where assessment.ProjectId == projectId
select new QuestionModel
{
Id = question.Id,
QuestionOrder = question.QuestionOrder,
QuestionText = question.QuestionText,
SelfNote = null, // Assessor's old note
OtherNotes = null // Other assessors' notes
};
How do I fill the null parts?
Here are my domain classes:
public class Question
{
public string Id { get; set; }
public int QuestionOrder { get; set; }
public string QuestionText { get; set; }
}
public class QuestionScore
{
public string Id { get; set; }
public string AssessmentId { get; set; }
public string QuestionId { get; set; }
public string AssessmentNote { get; set; }
}
public class Assessment
{
public string Id { get; set; }
public string ProjectId { get; set; }
public string AssessorId { get; set; }
}

Using Dapper with multiple inner joins

I am trying to use Dapper with the following sql string but I am unable to get it work:
string groupsStringDetailed = "SELECT SUSERGROUP.NAME, SUSERGROUP.DESCRIPTION, SPROGRAMS.PROGRAMNAME, SOBJECTS.NAME FROM ((SIDE.SADMIT SADMIT " +
"INNER JOIN SIDE.SOBJECTS SOBJECTS ON (SADMIT.PROGRAMID=SOBJECTS.PROGRAMID) AND (SADMIT.OBJECTID=SOBJECTS.ID)) " +
"INNER JOIN SIDE.SUSERGROUP SUSERGROUP ON SADMIT.GROUPID=SUSERGROUP.GROUPID) " +
"INNER JOIN SIDE.SPROGRAMS SPROGRAMS ON SOBJECTS.PROGRAMID=SPROGRAMS.ID " +
"WHERE SUSERGROUP.NAME NOT LIKE '%REPORT' ORDER BY SUSERGROUP.NAME, SPROGRAMS.PROGRAMNAME";
I have the following model classes:
public class SAdmit
{
public int GROUPID { get; set; }
public int OBJECTID { get; set; }
public int PROGRAMID { get; set; }
}
public class SObjects
{
public int ID { get; set; }
public int PROGRAMID { get; set; }
public string NAME { get; set; }
}
public class SPrograms
{
public int ID { get; set; }
public string PROGRAMNAME { get; set; }
}
public class SUserGroup
{
public int GROUPID { get; set; }
public string NAME { get; set; }
public string DESCRIPTION { get; set; }
public int VWLISTDEPTH { get; set; }
public int WDNBDAYHISTORY { get; set; }
public string RPDIRECTORY { get; set; }
public string SENDEREMAIL { get; set; }
public int CONNECTION_TIMEOUT { get; set; }
public int APPROVALSTATUS { get; set; }
}
I createad a custom group class hoping to map easier those models:
public class CustomSGroup
{
public SUserGroup Group { get; set; }
public SPrograms Programs { get; set; }
public SObjects Objects { get; set; }
}
I am trying to use Dapper to get results I want like this:
var output = await cnn.QueryAsync<CustomSGroup, SAdmit, SObjects, SPrograms, CustomSGroup>(groupsStringDetailed, (g, a, o, p) =>
{
a.PROGRAMID = o.PROGRAMID;
a.OBJECTID = o.ID;
a.GROUPID = g.Group.GROUPID;
o.PROGRAMID = p.ID;
return g;
}, splitOn: "PROGRAMID, OBJECTID, GROUPID, NAME");
but I am unable to see the big picture and what I am doing wrong because it throws an exception
"When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id\r\nParameter name: splitOn"
I am able to use Dapper with a simpler (one) inner join sql string, but this one I cannot get it work.
I reviewed the code and I've come to the conclusion that you simply are not including the fields you need to split on. Add the following fields to your query (perhaps adding distinct labels for the types that share similar field names.
PROGRAMID, OBJECTID, GROUPID, NAME

Relational Data DTO in MVC Web API 2

I am new to MVC, and learning as i go, but I am struggling to get to grips with DTO's with Web api.
I have 2 tables, one Schools, one students.
The School table has a one to many relationship with the Student table.
I can't seem to get the api response the way I want it.
This is the School DTO
public class SchoolDTO
{
public string schoolCode { get; set; }
public string schoolName{ get; set; }
public string studentNames { get; set; } // the related data
}
And this is what I am trying to do to populate it -
var schoolWithStudents = from b in context.Schools
select new SchoolDTO()
{
schoolCode = b.schoolCode,
schoolName= b.schoolName,
studentNames = b.Student.studentName
};
The response i am trying to get is something like this -
School
{schoolCode, schoolName}
StudentNames
[{…},{..}]
}
If you want to display student names which belong to a school, why studentNames property of SchoolDTO class is of type string ? It should be List<string>:
public class SchoolDTO
{
public string schoolCode { get; set; }
public string schoolName { get; set; }
public List<string> studentNames { get; set; }
}
And your Database Model should be something like that:
public class School
{
[Key] //I assume it is a PK
public string schoolCode { get; set; }
public string schoolName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
[Key]
public Guid studentId { get; set; }
public string studentName { get; set; }
public string schoolCode { get; set; }
[ForeignKey("schoolCode")]
public virtual School School { get; set; }
}
So you can query the database like this:
var schoolWithStudents = context.Schools.Select(q => new SchoolDTO
{
schoolCode = q.schoolCode,
schoolName= q.schoolName,
studentNames = q.Students.Select(w => w.studentName).ToList()
})
.ToList();

How to join tables using LINQ to Entities query?

I have a simple db structure:
public class Person
{
[Key]
public int PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Transport
{
[Key]
public int TransportID { get; set; }
public string Model { get; set; }
public string Brand { get; set; }
}
public class Accident
{
[Key]
public int AccsidentID { get; set; }
public DateTime AccidentDate { get; set; }
public int TransportID { get; set; }
[ForeignKey("TransportID")]
public virtual Transport Transport { get; set; }
public int PersonID { get; set; }
[ForeignKey("PersonID")]
public virtual Person Person { get; set; }
}
I need to create a list of accidents, wich I could pass to WPF form (using MVVM)
First I created new class witch I would like to see in my GridControl
public class AccsidentObject
{
[Key]
public int AccidentID { get; set; }
public DateTime AccidentDate { get; set; }
public int TransportID { get; set; }
public string Model { get; set; }
public string Brand { get; set; }
public int PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Could you please give me examples:
if I want to get list of all values from Accident table including data from Transport and Person tables
if I want to get Accident list grouped by TransportID (also include data from Person and Transport tables)
I am getting data from Linq query:
var result = from ac in DBContext.Accidents select ac;
List<Accident> accidentList = result.toList();
But I need to add some fields to list from other tables, what would be a code?
What do I do wrong and could not construct a list of AccidentObject, maybe there are some mistake in my DBContext, lists o something... Could you please help me to understand List elements??
Considering to 2 part I wrote:
var result = from ac in DBContext.Accidents select ac;
result = result.GroupBy(g => g.TransportID).toList();
And now I need to add some Transport details and format AccsidentObject list ...
To get an entity (or collection of entities) with associations eagerly populated use the Include extension method, or include in a final projection into your type:
var res = await (from a in ctx.Accidents
select new AccsidentObject {
AccidentID = a.AccidentID,
TransportID = a.Transport.TransportID,
Model = a.Transport.Model,
// …
}).ToListAsync();
You can use groupby in a LINQ comprehension expression to group by something. In the result the Key property is the thing grouped by and each instance is a collection of all things grouped by.
var res = await (from a in ctx.Accidents
group by a.TransportID into g
select new {
TransportID = g.Key,
Accidents = g
}).ToListAsync();
In the resulting anonymous types the Accidents property with be a collection of Accident.
var accidents = DBContext.Accidents.Select( a => new AccidentObject
{
AccidentID = a.AccidentId,
AccidentDate
TransportID
Model
Brand = a.Transport.Brand,
PersonID = a.Person.PersonID,
FirstName
LastName
});
and fill in the blanks in much the same way.
here's a linq example without using lambda expressions, that includes a group by clause if you prefer it: Linq to sql select into a new class

Categories

Resources