DbSet property of type class returns null - entity-framework

I'm creating an API for an app. The DbContext I have trouble with looks like this:
public class SchoolPlannerDbContext : DbContext
{
public SchoolPlannerDbContext(DbContextOptions<SchoolPlannerDbContext> options) : base(options) { }
public DbSet<Activity> Activities { get; set; }
public DbSet<Room> Rooms { get; set; }
public DbSet<Subject> Subjects { get; set; }
public DbSet<Teacher> Teachers { get; set; }
public DbSet<Group> Groups { get; set; }
}
The Activity class is as follows:
public class Activity
{
public int ID { get; set; }
[Required]
public Teacher Teacher { get; set; }
[Required]
public Room Room { get; set; }
[Required]
public Subject Subject { get; set; }
[Required]
public Group Group { get; set; }
[Required]
public int Slot { get; set; }
[Required]
public int Day { get; set; }
}
All the other properties contain an int ID and a string Name.
My controller looks like this:
public class SqlPlannerData : ISchoolPlannerData
{
private readonly SchoolPlannerDbContext db;
public SqlPlannerData(SchoolPlannerDbContext db)
{
this.db = db;
}
public IEnumerable<Activity> GetActivities()
{
return db.Activities;
}
public IEnumerable<Group> GetGroups()
{
return db.Groups;
}
}
GetGroups() works as intended and returns an IEnumerable with properties set correctly.
My problem is that when I'm trying to access db.Activities, the properties of type, say, Teacher (non-basic types like int) are set to null:
Debugger screenshot.
However, there is a row in the database that looks like this. I.e. the columns exist in the database.
What do I do to make GetActivities() return an IEnumerable with correctly set properties?

Some properties are null because of lazy loading you need to include them
return db.Activities
.Include(i => i.Teacher)
.Include(i => i.Room)
.Include(i => i.Subject)
.Include(i => i.Group)
.ToList()
Each propety Id can be configured by EF5+ as shadows. But I usually prefer to add all Ids explicitely. This way I have much less problem when I am using db context in the project. But is is optional and you can leave it as is
public class Activity
{
public int ID { get; set; }
[Required]
public int? TeacherId { get; set; }
[Required]
public int? RoomId { get; set; }
[Required]
public int? SubjectId { get; set; }
[Required]
public int? GroupId { get; set; }
public virtual Teacher Teacher { get; set; }
public virtual Room Room { get; set; }
public virtual Subject Subject { get; set; }
public virtual Group Group { get; set; }
[Required]
public int Slot { get; set; }
[Required]
public int Day { get; set; }
}
and in order to get list activities you have to add ToList() or ToArray() at least
public IEnumerable<Activity> GetActivities()
{
return db.Activities.ToArray();
}
and by the way, you can' t using not nullabe Id as required becaue it is relevant
[Required]
public int TeacherId { get; set; }
since int by default is 0 and it is a valid value and required will not be working

Related

Two tables (One To Many) And table with many have (One To Zero Or One) with the table One

Two Tables One To Many
VehicleStatus {Id , LastVehicleStatusUpdateId}
VehicleStatusUpdated {Id, VehicleStatusId, IsResponse }
I need to make (one to zero or one) to last record in VehicleStatusUpdated ...
LastVehicleStatusUpdateId ==> Navigator To VehicleStatus
like This
How can i make it with Entity Framework Annotation ??!!
public class Vehicle : IEntity<int>
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Number { get; set; }
public virtual VehicleStatus VehicleStatus { get; set; }
}
public class VehicleStatus : IEntity<int>
{
[ForeignKey("Vehicle")]
public int Id { get; set; }
public virtual Vehicle Vehicle { get; set; }
public int? LastVehicleStatusUpdateId { get; set; }
[ForeignKey("LastVehicleStatusUpdateId")]
public virtual VehicleStatusUpdate LastVehicleStatusUpdate { get; set; }
public virtual List<VehicleStatusUpdate> VehicleStatusUpdates { get; set;
}
public class VehicleStatusUpdate : IEntity<int>
{
[ForeignKey("LastVehicleStatus")]
public int Id { get; set; }
public DateTime UpdatedTime { get; set; }
public bool IsResponse { get; set; }
public int VehicleStatusId { get; set; }
[ForeignKey("VehicleStatusId")]
public virtual VehicleStatus VehicleStatus { get; set; }
}
I Tried this i got =>
Unable to determine the relationship represented by navigation property 'VehicleStatus.LastVehicleStatusUpdate' of type 'VehicleStatusUpdate'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

LINQ query throw exception on FirstOrDefault method

I'm using EF core, and I have a many-to-many relationship between two entity
IotaProject <--> User
Here's entities & dto related to the question
public class IotaProject
{
[Key]
public int Id { get; set; }
[Required]
public string ProjectName { get; set; }
[Required]
public DateTime Create { get; set; }
public ICollection<ProjectOwnerJoint> Owners { get; set; } = new List<ProjectOwnerJoint>();
}
public class ProjectOwnerJoint
{
public int IotaProjectId { get; set; }
public IotaProject IotaProject { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User
{
[Key]
public int Id { get; set; }
[Required]
public string FullName { get; set; }
[Required]
public string ShortName { get; set; }
[Required]
public string Email { get; set; }
public ICollection<ProjectOwnerJoint> OwnedProjects { get; set; } = new List<ProjectOwnerJoint>();
}
public class ApplicationDbContext : DbContext
{
public DbSet<IotaProject> IotaProjects { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<ProjectOwnerJoint> ProjectOwnerJoint { get; set; }
}
public class IotaProjectDisplayDto
{
public int Id { get; set; }
public string ProjectName { get; set; }
public DateTime Create { get; set; }
public UserMinDto Owner { get; set; }
public int Count { get; set; }
public IEnumerable<UserMinDto> Reviewers { get; set; }
}
public class UserMinDto
{
public int Id { get; set; }
public string FullName { get; set; }
public string ShortName { get; set; }
}
Following LINQ is the problem, the LINQ purpose is to convert IotaProject to IotaProjectDisplayDto, and key part is that Owners property of IotaProject is ICollection and Owner property in IotaProjectDisplayDto is just one single element UserMinDto, so I only need to get the first element of IotaProject's Owners and that's FirstOrDefault() comes.
IEnumerable<IotaProjectDisplayDto> results = _db.IotaProjects.Select(x => new IotaProjectDisplayDto
{
Id = x.Id,
ProjectName = x.ProjectName,
Create = x.Create,
Owner = x.Owners.Select(y => y.User).Select(z => new UserMinDto { Id = z.Id, FullName = z.FullName, ShortName = z.ShortName }).FirstOrDefault()
});
return results;
it throws run-time exception
Expression of type 'System.Collections.Generic.List`1[ToolHub.Shared.iota.UserMinDto]' cannot be used for parameter
of type 'System.Linq.IQueryable`1[ToolHub.Shared.iota.UserMinDto]'
of method 'ToolHub.Shared.iota.UserMinDto FirstOrDefault[UserMinDto](System.Linq.IQueryable`1[ToolHub.Shared.iota.UserMinDto])' (Parameter 'arg0')
I'm guessing it's probably related to deferred execution, but after read some posts, I still can't resolve it.
Any tips would be appreciated.
Right now, the only way I can get this work is I change type of Owner property in IotaProjectDisplayDto into IEnumrable, which will no longer need FirstOrDefault() to immediate execution. And later on, I manually get the first element in the client to display.
This issue happened in Microsoft.EntityFrameworkCore.SqlServer 3.0.0-preview7.19362.6
I end up downgrade to EF core stable 2.2.6 as Ivan suggested in comment, and everything works fine.

Microsoft Entity Framework Core Parent with 2 Children [duplicate]

This question already has answers here:
EF Core returns null relations until direct access
(2 answers)
Closed 4 years ago.
So I have 3 classes:
public class OwnerDto
{
public int Id { get; set; }
public string Name { get; set; }
public string EmailAddress { get; set; }
}
public class SitterDto
{
public int Id { get; set; }
public string Name { get; set; }
public string EmailAddress { get; set; }
}
public class ReviewDto
{
public int Id { get; set; }
public int Rating { get; set; }
//[ForeignKey("OwnerId")]
public OwnerDto Owner { get; set; }
//[ForeignKey("SitterId")]
public SitterDto Sitter { get; set; }
}
But I can't figure out how to do the proper modelBuilder. Everything I tried fails :( I am learning so bear with me.
My closest attempt was this:
modelBuilder.Entity<ReviewDto>()
.HasOne(t => t.Owner).WithMany().HasForeignKey("OwnerId");
Basically Owner and Sitter are always null :( Should i keep the [ForeignKey()] stuff or should i use a different extension method?
Declare all classes with navigation properties to each other. Mark one of the tables (the dependent table) with the ForeignKey attribute on its Primary Key.
EF infers one-to-many from this:
public class OwnerDto
{
public int Id { get; set; }
public string Name { get; set; }
public string EmailAddress { get; set; }
public ICollection<ReviewDto> Reviewers{ get; set; }
public ICollection<SitterDto> Sitters{ get; set; }
}
public class SitterDto
{
public int Id { get; set; }
public string Name { get; set; }
public string EmailAddress { get; set; }
public int OwnerId{ get; set; }
[ForeignKey("OwnerId")]
public OwnerDto Owner { get; set; }
}
public class ReviewDto
{
public int Id { get; set; }
public int Rating { get; set; }
public int OwnerId{ get; set; }
[ForeignKey("OwnerId")]
public OwnerDto Owner { get; set; }
}
and EF infers one-to-one from this:
public class OwnerDto
{
...
public ReviewDto Review{ get; set; }
...
}
public class ReviewDto
{
[ForeignKey("Owner")]
public int OwnerId { get; set; }
public OwnerDto Owner{ get; set; }
...
}
You need to refer Eager Loading in this scenario, You can use the Include method to specify related data to be includethe d in query results.
var query = from review in context.Review.Include(o => o.Owner).Include(s=>s.Sitter) select review;

EF code first model not in sync with database

My EF Code First model for some reason is not in sync with the db. I'm getting this error:
{"Invalid column name 'Type_Id1'."}
The field is actually called 'Type_Id' so I'm not sure from where that 1 comes up. I have the table column called as Type_Id and also I've added a Type_Id in my type entity model.
Why might I be getting that error message, plus why I'm getting 1 at the end of the name?
Update
My Task class:
public class Task
{
public Task()
{
Language = 1;
Grades = new HashSet<Grade>();
Categories = new HashSet<Category>();
Subjects = new HashSet<Subject>();
Rooms = new Collection<Room>();
Tools = new Collection<Tool>();
}
[Key]
public int Id { get; set; }
public string Description { get; set; }
public virtual TaskType Type { get; set; }
public string Rules { get; set; }
[Required]
[StringLength(200), MinLength(1)]
public string Name { get; set; }
public int PreperationTime { get; set; }
public int InstructionTime { get; set; }
public int TaskTime { get; set; }
public int Type_Id { get; set; }
public string VideoLink { get; set; }
[Required]
public int Language { get; set; }
public int? MinimumParticipants { get; set; }
public int? MaximumParticipants { get; set; }
public int? Rating { get; set; }
[Required]
public string CreatedBy { get; set; }
public virtual ICollection<Grade> Grades { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Subject> Subjects { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public virtual ICollection<Tool> Tools { get; set; }
}
DBContext class:
public ApplicationDbContext() : base("DefaultConnection", false)
{
}
public DbSet<Task> Tasks { get; set; }
public DbSet<TaskType> TaskTypes { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
You need to add the FK attribute on your navigation property. EF is creating Type_Id1 because Type_Id already exists (although it can't tell by convention it is the FK).
[ForeignKey("Type_Id")]
public virtual TaskType Type { get; set; }
https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships

Entity framework foreign key

I have 2 classes
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
and
public class PersonWebsite
{
public int Id { get; set; }
public string Website { get; set; }
public int PersonId{ get; set; }
}
I've seen stuff like this being done before
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public ICollection<PersonWebsite> PersonWebsites{ get; set; }
}
How could I go about implementing the code that when a Person is initialized, the PersonWebsites List will automatically be initialised and get all the PersonWebsite objects that have the same PersonId as the class that calls it.
Lazy Loading:
You can make PersonWebsites property virtual:
public virtual ICollection<PersonWebsite> PersonWebsites{ get; set; }
Entity framework will load it from the database as soon as it's required.
Also this method requires you to have lazy loading enabled which is by default:
DbContext.ContextOptions.LazyLoadingEnabled = true;
Eager Loading:
You can use include to force entity framework to load PersonWebsites on the first query:
DbSet.Include(p => p.PersonWebsites);
You may also want to change your PersonWebsite class like this, in order to navigate to the person from the PersonWebsite object (using Lazy-Loading):
public class PersonWebsite
{
public int Id { get; set; }
public string Website { get; set; }
[ForeignKey("Person")]
public int PersonId{ get; set; }
public virtual Person Person {get;set;}
}