Entity framework and Classes - c#

I am trying to learn Entity framework. Say, I have the following classes
class Course
{
[Key]
public virtual int CourseID {get; set;}
public virtual string CourseName {get; set;}
}
class CourseDBContext:DBContext
{
public DbSet<Course> Courses{get;set;}
}
Then I can use Linq to query the database as shown below
using (CourseDBContext a = new CourseDBContext())
{
var b = from c in a.Course
where c.CourseID == 1001
select c;
var d = b.FirstOrDefault();
if(d != null)
Console.WriteLine(d.CourseName);
}
This works fine. Now if I add a second class
class Assignment
{
[Key]
public virtual int CourseID {get; set;}
public virtual int StaffID {get; set;}
}
class AssignmentDBContext:DBContext
{
public DbSet<Assignment> Assignments{get;set;}
}
Now, How can I use Linq to select and display the CourseName and StaffID associated with CourseID = 1001?
The example above is contrived and so the table design and fields are irrelevant. I just want to know how to query the data between two classes from two different database tables using Entity Framework and Linq.
Thanks

Both entities need to be in the same context.
public class CoursesContext: DbContext
{
public DbSet<Assignment> Assignments {get; set;}
public DbSet<Course> Courses {get; set;}
}
You can add an Assignment navigation property to filter on a foreign key:
public class Course
{
[Key]
public virtual int CourseID {get; set;}
public virtual string CourseName {get; set;}
public virtual Assignment {get; set;}
}
Then you can query like so:
var staffId =
from c in a.Course
where c.CourseID == 1001
select c.Assignment.StaffID;

Don't have a seperate context for each DbSet. I.e
class MyDbContext : DBContext
{
public DbSet<Course> Courses{get;set;}
public DbSet<Assignment> Assignments{get;set;}
}

Related

How to get records from table that depends on another tables in entity framework core?

I want to get some records from Database that depends on three tables.
Three tables are:
1.Company(Id,Name)
2. Car(Id,CompanyId,Name)
3. Showroom(Id,CarId,Name)
Now a one company contains many cars and many cars may exist in many showrooms.
I want to get records from showroom table where company '2' cars exist along with cars. Is it possible to do it in entity framework core?
I think your entities will be like :
Company
public class Company
{
public int Id {get; set;}
public string Name {get; set;}
public ICollection<Car> Cars {get; set;}
}
Car:
public class Car
{
public int Id{get; set;}
public string Name {get; set;}
public int CompanyId{get; set;}
public Company Company {get; set;}
}
ShowRoom:
public class ShowRoom
{
public int Id{get; set;}
public string Name {get; set;}
public int CarId{get; set;}
public Car Car{get; set;}
}
In your method:
var context = new SomeContext();
var showRooms= context.ShowRooms
.Include(x=> x.Car)
.ThenInclude(x=> x.Company)
.Where(x=> x.Car.Company.Id== 2)
.ToList();

Class for joined tables

I have two tables that I need to join
employee
-id
-name
-department_id
and
department
-id
-department_name
How can I handle the joined data in a single class? Should I create properties for all the data for each table?
e.g
class employeerecord
{
private int id {get; set;}
private string name {get; set;}
private int department_id {get; set;}
private string department_name {get; set;}
}
Right now, I'm using a datatable for viewing joined tables.
The whole design should include all entities you have in your database, i.e. there's departament table, there should be corresponding class. Same applies to employee table. You should have following classes:
class Employee
{
public int id {get; set;}
public string name {get; set;}
public int department_id {get; set;}
public Departament department {get; set;}
}
class Departament
{
public int id {get; set;}
public string name {get; set;}
//public ICollection<Employee> Employees { get; set; }
}
When loading data, you should wirte join query, to populate both: Employee instance and Departament instance.
You can uncomment commented line, if you'd like to have list of employees in particular departament.
This solely depends on what you want to do with this classes. You can go either way.
If you want to display a single employee and that employee can only belong to one department, then nothing speaks against a flat model:
class employeerecord
{
private int id{get;set};
private string name{get;set;}
private int department_id{get;set;}
private string department_name{get;set;}
}
If an employee can be a member of multiple Departments, you are better off storing the departments in a collection:
public class EmployeeViewModel
{
public int id{get;set};
public string name{get;set;}
public IEnumerable<Deparment> Departments { get; set; }
}
The same goes for departments. A department will most likely consist of multiple employees:
public class DepartmentViewModel
{
public int id{get;set};
public string name {get;set;}
public IEnumerable<Employee> Employees { get; set; }
}
And there is no reason, why you can't do all at once and use the classes depending on your specific use case.

How to return this result using linq in entity framework( 2 foreign key mapping table)

I have a table that contains 2 foreign key that reference separately to 2 different table.
I would like to return the result of all person that has course of "Science".
How to retrieve the record back using LINQ?
This is what i gotten so far:
return
_ctx.Person
.Include(u => u.Course
.Where(ug=>ug.CourseName== "Science"));
This is not working as it shows the error.
The Include path expression must refer to a navigation property
defined on the type
public class Course
{
public int CourseID {get; set;}
public string CourseName {get; set;}
public virtual ICollection<Person> Persons { get; set; }
}
public class Person
{
public int PersonID {get; set;}
public virtual ICollection<Course> Courses { get; set; }
}
This is the mapping table. Only contains 2 foreign key from 2 different table.
I could not use this table inside the solution.As the code first won't generate this table as it doesn't contain it's own PK.
//This is not shown in the EntityFramework when generating Code First.
public class PersonCouseMap
{
public int PersonID {get; set;}
public int CourseID {get; set;}
}
Update : this works after I switched the entity.
return _ctx.Course
.Include(u=>u.Person)
.Where(ug=>ug.CourseName == "Sciene");
Anyone can explain why it won't work the another way round.
I need to display a List of Person who have course of "Science",
not Course Science that has a list of user.
The original query does not work because you've pushed the Where predicate inside the Include expression, which is not supported as indicated by the exception message.
The Include method is EF specific extension method used to eager load related data. It has nothing to do with the query filtering.
To apply the desired filter person that has course of "Science" you need Any based predicate since the Person.Courses is a collection:
return _ctx.Person
.Where(p => p.Courses.Any(c => c.CourseName == "Science"));
To include the related data in the result, combine it with Include call(s):
return _ctx.Person
.Include(p => p.Courses)
.Where(p => p.Courses.Any(c => c.CourseName == "Science"));
It looks like there is no relations between these two entites, you can establish a relationship by making the following changes to your code:
Here I am assuming that you want to establish Many-to-Many relationship between these two tables by having a third entity PersonCourseMap
public class Course
{
public int CourseID {get; set;}
public string CourseName {get; set;}
public virtual ICollection<CoursePersons> Courses { get; set; }
}
public class Person
{
public int PersonID {get; set;}
public virtual ICollection<PersonCourse> Courses { get; set; }
}
public class PersonCourseMap
{
public int PersonID {get; set;}
public int CourseID {get; set;}
public virtual ICollection<Person> Persons { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
After making above changes you can simply navigate through properties.
Include Foreign Key Mapping
public class Course
{
public int CourseID {get; set;}
public string CourseName {get; set;}
public virtual ICollection<Person> Person {get; set}
}
public class Person
{
public int PersonID {get; set;}
public virtual ICollection<Course> Course {get; set;}
}
using System.ComponentModel.DataAnnotation.Schema;
public class PersonCouseMap
{
[ForeignKey("Person")]
public int PersonID {get; set;}
[ForeignKey("Course")]
public int CourseID {get; set;}
public virtual ICollection<Person> Person {get; set;}
public virtual ICollection<Course> Course {get; set;}
}

Bridge table that join multiple tables

I've a Product table and a Feature table that are joined together using a bridge table, ProductFeature. Below are simplified version of these three tables. These works fine. No problem here.
[Table("Products")]
public partial class ProductEntity
{
public int Id { get; set; }
public string Code { get; set; }
public ICollection<ProductFeatureEntity> productFeatures {get; set;}
}
[Table("Features")]
public partial class FeatureEntity
{
public int Id { get; set; }
public string Code { get; set; }
public ICollection<ProductFeatureEntity> productFeatures {get; set;}
}
[Table("ProductFeatures")]
public partial class ProductFeatureEntity
{
[Key, Column(Order = 1)]
public int ProductId { get; set; }
[Key, Column(Order = 2)]
public int FeatureId { get; set; }
public int SequenceNbr {get; set;}
public ProductEntity Product {get; set;}
public FeatureEntity Feature {get; set;}
}
But now, I need to make that same bridge table to also be able to join the Product table itself. Another word, I need to change from "Product can have multiple Features" to "Product can have multiple features and can also have multiple sub-product". I need to use the same bridge table because I need to know the sequence, which is controlled by SequenceNbr field, of each features and sub-products. Is it possible to do this in EF?
you can add ParentId to ProductEntity
and use this in Configuration Class:
HasMany(x => x.ProductEntity).WithOptional()
.HasForeignKey(x => x.ParentId);
Or
Use this in OnModelCreating method in DbContext:
modelBuilder.Entity<ProductEntity>()
.HasOptional().WithMany().HasForeignKey(x=>x.ParentId)

How to avoid circular references with AutoMapper?

I have the following models (and corresponding DTOs):
public class Link
{
public int Id {get; set;}
public int FirstLinkId {get; set;}
public int SecondLinkId {get; set;}
public virtual Link FirstLink {get; set;}
public virtual Link SecondLInk {get; set;}
}
public class OtherObject
{
public int Id {get; set;}
public int LinkId {get; set;}
public string Name {get; set;}
public virtual Link Link {get; set;}
}
In my scenario, I can have a Link object where FirstLink and/or SecondLink can be null, references to other objects, or references to the same object.
Now I want to load an OtherObject entity from the db using EF. I load the entity itself and also the Link object associated with it. This is done perfectly by EF.
In this particular case, both FirstLink and SecondLink are the same as Link, therefore, when automapping from model to dto it just keeps on mapping into oblivion.
My mapping is:
Mapper.CreateMap<OtherObject, OtherObjectDto>().Bidirectional()
.ForMember(model => model.LinkId, option => option.Ignore());
where Bidirectional() is this extension:
public static IMappingExpression<TDestination, TSource> Bidirectional<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
return Mapper.CreateMap<TDestination, TSource>();
}
Is there way to tell Automapper not to map further down the tree in this case?
The way I would handle this is to create separate DTO objects for the children:
public class Employee
{
public int Id {get; set;}
public string Name { get; set; }
public Employee Supervisor {get; set; }
}
public class EmployeeDto {
public int Id {get; set;}
public string Name { get; set; }
public SupervisorDto Supervisor { get; set; }
public class SupervisorDto {
public int Id {get; set;}
public string Name { get; set; }
}
}
Mapper.CreateMap<Employee, EmployeeDto>();
Mapper.CreateMap<Employee, EmployeeDto.SupervisorDto>();
Don't let your DTOs be recursive/self-referential. Be explicit in your structure on how deep you want it to go.
EF can't do recursive joins, you're only doing one level, so don't make your DTOs go nuts with infinitely deep relationships. Be explicit.

Categories