Lazy loading not working in Entity Framework - asp.net

I have two classes that are connected by using the virtual keyword:
Student:
public class Student
{
public int StudentId{get; set;}
public string LastName { get; set; }
public string FirstName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual IEnumerable<Enrollment> Enrollments { get; set; }
}
Enrollment:
public class Enrollment
{
public int EnrollmentId { get; set; }
public int CourseId { get; set; }
public int StudentId { get; set; }
public decimal? Grade { get; set; }
public virtual Course course { get; set; }
public virtual Student student { get; set; }
}
Both tables are populated, and have corresponding records (for instance, there is a student with id 1 and enrollments for student with id 1).
I'm pulling up a student by it's id and sending it to a view
Student student = db.Students.Find(id);
return View(student);
In the view I can display the details for that student. The #Model does contain an Enrollment property (at least it comes up in intellisense and doesn't red-line), but it is Null.
There is also a course class:
{
public int CourseId { get; set; }
public String CourseName { get; set; }
public int TotalCredits { get; set; }
}
Since #Model.Enrollments is Null, I can't access #Model.Enrollment.CourseNamae.
Edit:
I just tried a hack workaround:
IEnumerable<Student> temp = db.Students.Include(s => s.Enrollments);
Student student = temp.FirstOrDefault(s => s.StudentId.Equals(id));
return View(student);
This is giving me the error on the second line:
System.InvalidOperationException: A specified Include path is not valid. The EntityType 'MyFirstProject2.Models.Student' does not declare a navigation property with the name 'Enrollments'.
Does that offer any clues?

A little bit late but here some explanation between Lazy Loading vs Eager Loading
And also the Rules for lazy loading:
context.Configuration.ProxyCreationEnabled should be true.
context.Configuration.LazyLoadingEnabled should be true.
Navigation property should be defined as public, virtual. Context will NOT do lazy loading if the property is not define as
virtual.
EDIT:
One last thing for relationships use:
public virtual ICollection<Enrollment> Enrollments { get; set; }
Other Links:
Lazy Loading
Eager Loading
Explicit Loading

Related

Many-to-many relations in Entity Framework

I have an issue with many-to-many relations.
I have 3 model classes:
Article - >>> Item
Keyword - >>> Keyword
TableForRelation between Articles And Keywords - >>> ItemKeywords
With Entity Framework Core, I write these 3 classes and they work fine
public class Item
{
public int Id { get; set; }
public string Content { get; set; }
public virtual ICollection<ItemKeyWords> ItemKeyWords { get; set; }
}
public class KeyWord
{
public int Id { get; set }
public string Text { get; set; }
public virtual ICollection<ItemKeyWords> ItemKeyWords { get; set; }
}
public class ItemKeyWords
{
public int Id { get; set; }
public int ItemId { get; set; }
public virtual Item Item { get; set; }
public int KeyWordId { get; set; }
public virtual KeyWord KeyWord { get; set; }
}
Question is: how can I tell Entity Framework if Keyword exists do not put that in keyword table and just create a relation to that in ItemKeywords table.
database uml
before to add a KeyWord to Item.ItemKeyWords you have to try to load it from context.Set<KeyWord>().
If the load results on a null, then do as actually.
If the load != null then add the loaded value.

ASP.NET Core Conflict with Foreign Key

I have got several models:
Course.cs
public class Course
{
public Guid Id { get; set; }
public ICollection<ApplicationUser> Teacher { get; set; }
public string Name { get; set; }
public string ShortName { get; set; }
public DateTime CreationDate { get; set; }
public bool IsActive { get; set; }
}
Group.cs
public class Group
{
public Guid Id { get; set; }
public ApplicationUser Mentor { get; set;}
public string DisplayName { get; set; }
public string GroupName { get; set; }
public DateTime StartYear { get; set; }
public string InviteCode { get; set; }
public ICollection<ApplicationUser> Students { get; set; }
public ICollection<Course> Courses { get; set; }
}
ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
[Required]
public string Firstname { get; set; }
[Required]
public string Surname { get; set; }
public bool Gender { get; set; }
public DateTime Birthdate { get; set; }
//[Required]
public string InviteCode { get; set; }
public Guid GroupId { get; set; }
[ForeignKey("GroupId")]
public Group CurrentGroup { get; set; }
public ICollection<Group> PastGroups { get; set; }
}
Now when I try to register (using Identity) a user (not even trying to give the user a group) I receive this error:
SqlException: The INSERT statement conflicted with the FOREIGN KEY
constraint "FK_AspNetUsers_Groups_GroupId". The conflict occurred in
database "aspnet-Project_Dojo-3af15f80-8c62-40a6-9850-ee7a296d0726",
table "dbo.Groups", column 'Id'. The statement has been terminated.
In my modelBuilder I have added some logics for the relations between Group, ApplicationUser (Students) and the Foreign Key:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);\\
builder.Entity<ApplicationUser>()
.HasOne(p => p.CurrentGroup)
.WithMany(b => b.Students)
.HasForeignKey(p => p.GroupId);
}
I don't know what this is exactly doing, but I've been browsing some Stackoverflow threads to come to this code (migrations weren't working without it).
I look forward to a solution for my problem. Once again, I'm not doing ANYTHING with the groups yet when registering.
Thanks in advance!
not even trying to give the user a group
Well there's your problem, it's required.
Either provide a group, or make it optional by making the foreign key nullable (Guid? GroupId).
Because it's currently a non-nullable struct, it'll have a default value of all zeroes (Guid.Empty). This FK is not known in your database, resulting in the error you see.

Exclude underlying objects when storing data using EF6

I have a class Ticket which has some properties. Three of these (View, Task and Key) properties are navigation properties. Those properties already exist in database even before a ticket has been stored. In my application I load those properties from the database first and then create a Ticket object. I need to save only the ticket (not the underlying objects ) to the database with the id to Key, View and Task (these are primery keys in the Ticket table)
[Table("Tickets")]
public class Ticket
{
[Key]
public int Id { get; set; }
public DateTime? Created { get; set; }
[Required]
public View View{ get; set; }
[Required]
public Key Key { get; set; }
public Task Task { get; set; }
}
I try to save the Ticket object like this:
db.Tickets.Add(ticket);
db.Entry(ticket.Key).State = System.Data.Entity.EntityState.Unchanged;
db.Entry(ticket.View).State = System.Data.Entity.EntityState.Unchanged;
db.Entry(ticket.Task).State = System.Data.Entity.EntityState.Unchanged;
db.SaveChanges();
When I try this approach I get the error:
{"Message":"An error has occurred.","ExceptionMessage":"Saving or accepting changes failed because more than one entity of type 'Key' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption\" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.","
Is it even possible to work with Entity Framework this way? Having pre defined data which is loaded to it's objects (Key, View, Task) first and later assign these objects to an object having these properties but then in the entity framework context only adding the parent object, in this case the ticket?
I have also tried to set the underlying objects to null but then I will loose the data for those underlying objects, data I need later on in the application.
This is how the underlying objects look like:
[Table("Views")]
public class View
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Version { get; set; }
[Required]
public DateTime? Created { get; set; }
}
[Table("Keys")]
public class Key
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Version { get; set; }
[Required]
public DateTime? Created { get; set; }
}
[Table("Tasks")]
public class Task
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Version { get; set; }
[Required]
public DateTime? Created { get; set; }
}
Try adding Foreign Keys to your object and making those required instead of making the navigation property required. Like so:
[Table("Tickets")]
public class Ticket
{
[Key]
public int Id { get; set; }
public DateTime? Created { get; set; }
[Required]
public int ViewId {get; set; }
[ForeignKey("ViewId")]
public View View{ get; set; }
[Required]
public int KeyId {get; set; }
[ForeignKey("KeyId")]
public Key Key { get; set; }
public Task Task { get; set; }
}

Navigation property from dependent to principal

I have two Entities
public class Person
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
public virtual int ID { get; set; }
public virtual string Code { get; set; }
public virtual int PersonId { get; set; }
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
}
in my business first we create person then we create an employee by selecting a person, while selecting person for the employee i want to select only the persons who are not associated to employee, i couldn't figure how to configure the Employee property in Person Entity
If you are selecting people that aren't related to a specific employee then you shouldn't have a property for that. You should only have link to related entities. Try doing this in LINQ it should get you all people that don't have a relation to an employee.
var people = context.People.Where(x => x.Employee == null);
public class Person
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
public virtual int ID { get; set; }
public virtual string Code { get; set; }
public virtual int PersonId { get; set; }
[ForeignKey("PersonId")]
[InverseProperty("Employee")]
public virtual Person Person { get; set; }
}
Think that should do it, inverse property creates the mapping so only needs to be done from one side.
Hope this is what you were looking for.
I figured out an answer, don't know if it's the best!
jobQuery = jobQuery.Where(jb => !Context.Employees.Any(emp => emp.JobId == jb.Id));

Alter primary key with Entity Framework

First of all ASP.NET and MVC 4 are very new to me (+- one month) and sorry if its a bad question.
I've got two classes "Turma" and "Curso"
public class Turma
{
[Key]
public int idCurso { get; set; }
public string RefTurma { get; set; }
public Curso Curso { get; set; }
public string NomeCurso { get; set; }
}
and
public class Curso
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int idArtigoAT { get; set; }
public string ConteudoPrograma { get; set; }
public virtual ICollection<Turma> Turmas { get; set; }
}
After this I started a migration and updated the database. So far so good, but then problems.
Due to new information the primary key type should be varchar(18). I've tried to change but so far without success.
Any ideia or solution???
No, what you want is an 'Id' property and an 'MyCustomUniqueName' property. this custom property, should be and unique index in database. this is the best design for this situation IMHO.

Resources