Entity Framework 4.1 - Segregating an entity into multiple tables (Code-First) - asp.net-mvc-3

I'm trying to find out how I can re-use a simple 'Comment' entity type for multiple scenarios where something is 'commentable' in my application.
At the moment, I have a couple of entities that a user is able to post comments to. Examples include Blogs, Profiles and Photos - these can all be 'commented' on.
I'd like to be able to use the same 'Comment' class for each of these scenarios, but I don't want to end up with one HUGE table full of comments for everything. I figure it would be much more efficient to at least store a table of BlogComments, PhotoComments, and ProfileComments. At the moment, my Comment class looks like this:
public class Comment
{
[Key]
public int Id { get; set; }
public int ContextId { get; set; }
[StringLength(256)]
public string Content { get; set; }
public DateTime DatePosted { get; set; }
public virtual Member Author { get; set; }
}
Presumably, I'd need the 'ContextId' field to refer to the particular thing being commented on. This Id might be the Id of a Blog, a Profile or a Photo. I was hoping to be able to refer to comments much like a normal ICollection in these classes, and I have some code like this for the Photos as an example:
public class Photo
{
[Key]
public int Id { get; set; }
[StringLength(48)]
public string FileName { get; set; }
public virtual Member Owner { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
I've been pointed to various articles during my searches, but none really seem relevant to my particular situation. How can I map these comment collections to different tables, and avoid having a comment "super-table"?
Any help, pointers or advice would be hugely appreciated :)

You can create an abstract Comment class and inherit from it specific comments such as PhotoComment, ProfileComment. You will be able to map the comments to different tables.
public abstract class Comment
{
[Key]
public int Id { get; set; }
[StringLength(256)]
public string Content { get; set; }
public DateTime DatePosted { get; set; }
public virtual Member Author { get; set; }
}
public class PhotoComment : Comment
{
public int PhotoId { get; set; }
public virtual Photo Photo { get; set; }
}
public class Photo
{
[Key]
public int Id { get; set; }
[StringLength(48)]
public string FileName { get; set; }
public virtual Member Owner { get; set; }
public virtual ICollection<PhotoComment> Comments { get; set; }
}

Related

Can't Include navigation property (it is null) [duplicate]

This question already has answers here:
How to stop self-referencing loop in .Net Core Web API?
(4 answers)
Closed 4 years ago.
I am trying to get the students from the database and also include the course entities corresponding to them, but it seems that I'm doing something wrong.
this is student class:
public class Student
{
public int StudentID { get; set; }
public string Name { get; set; }
public int CourseID { get; set; }
public virtual Course Course { get; set; }
}
this is course class:
public class Course
{
public int CourseID { get; set; }
public string Name { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
and I retrive the collection of student entities as shown below:
context.Students.Include(i => i.Course).ToList();
If I remove the include method, then I get data, but course property of student object is null.
P.S I am testing it with Postman and with "Include" I am not able to get anything.
If I comment this
public virtual ICollection<Student> Students { get; set; }
everything works fine.
I put the full code on github:
https://github.com/AlexDev5/Problem
You have to configure the serializer to ignore circular references in your project.
So for this you have to add following line of code inside ConfigureServices method in Startup.cs
Like
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
}
Depending on the sample found here https://github.com/aspnet/EntityFramework.Docs/tree/master/samples/core/Querying/Querying
I wrote one solution, but I don't know if it is good approach for this problem:
I created StudentCourse class and defined it as shown below:
public class StudentCourse
{
public int StudentCourseID { get; set; }
public int StudentID { get; set; }
public Student Student{ get; set; }
public int CourseID { get; set; }
public Course Course { get; set; }
}
And I modified the Course class as shown below:
public class Course
{
public int CourseID { get; set; }
public string Name { get; set; }
public virtual ICollection<StudentCourse> Students { get; set; }
}

EF Code First and linq extension methods - foreign keys, am i doing it wrong?

I have something like this: (pseudocode)
public class Author
{
int id;
public List<Thread> Threads;
public List<ThreadPoints> ThreadPointses;
}
public class Thread
{
int id;
public List<ThreadPoints> ThreadPointses;
}
public class ThreadPoints
{
int id;
int Points;
}
And i am not sure if above is correct, but now i would want to obtain number of points' that specified Author have in specified Thread.
I cannot directly call ThreadPoints.Thread_id, because it's not accessible, even if it physically is in the database.
So do i need to change my model, or am i unaware of some useful methods?
So basically, my model looks like that:
public class Account
{
[Key]
public Guid AccountId { get; set; }
public string UserName { get; set; }
public List<Post> Posts { get; set; }
public List<Post> ModifiedPosts { get; set; }
public List<Thread> Threads { get; set; }
public List<ThreadPoints> ThreadPointses { get; set; }
public List<Thread> LastReplied { get; set; }
public int Points { get; set; }
}
public class Thread
{
[Key]
public int Id { get; set; }
public List<ThreadPoints> ThreadPointses { get; set; }
public List<Post> Posts { get; set; }
public int CurrentValue { get; set; }
public int NumberOfPosts { get; set; }
public int TotalValue { get; set; }
public int Views { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
}
public class ThreadPoints
{
[Key]
public int Id { get; set; }
public int Points { get; set; }
}
And what i need, is, when user creates a thread, he gives some amount of points into it. In the next action, i want to take that amount of points (from database), and increase it. But i only have thread id as input information.
Your answer might be good, (as far i am trying to implement it), but anyways, i am not sure about this model. Maybe i should manually add foreign keys into my model? It surely would be simpler, but then i would have two foreign keys in my database...
Since you're not explicitly mapping your FK's, entity framework is generating them and hiding them away, so to get to the Id's of the properties, you'll need to follow the navigation collections.
I'm not sure about your question, but are you wanting the number of Points, inside of a specific Threadpoint for a given author? Your model doesn't seem to support this very well, but you could do something like this-
public int GetPoints(Author author, Thread thread)
{
int points = author.Threads.FirstOrDefault(t => t.id == thread.id).ThreadPointses.Sum(tp => tp.Points);
}
This would return the sum of all the points contained in the list of threadpoints, which are contained in the list of threads with the same id as the thread you passed in, for the specified author.
If this doesn't work for you - can you post your actual model?

Entity doubts - following Contoso University Tutorial

I've been following the contoso university tutorial on Microsoft´s site and I have some doubts about how the Entity Framework is doing some stuff. Here we go...
On the beginning of the tutorial, we created three classes that will be turned into tables in my database.
I´d like to know when and how entity instantiates my classes to populate the objects.
Im using code-first approach.
Example:
The classes im using:
public class Course
{
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
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; }
}
public class Student
{
public int StudentID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
After following the tutorial I can now list all my Students and theirs respectives Course(s), as well as their properties in enrollments lists.
When did entity instantiated my Student classes and populated it with the respective Enrollment(s) lists?
How does it know what enrollments are linked to that student?
I dont see any new constructor() ever beeing called.
This might be simple but Im kinda lost here.
Thanks
It doesn't instantiate anything ahead of time, and it doesn't have to. And there won't be anything in the table representing the virtual property as such, either.
These virtual properties are used by EF at runtime to store navigation information, and the collections can be null or contain 0 or more elements. There's no magic, it's just by design that EF "new"s up the collection when it needs to.
If you want to be explicit about it, you can create a constructor on your POCO as well and set your collection equal to a new hashtable.

EF multiple relationships between entities

I'm using the Code First approach to build the database in this problem. I have the following (partial) entity:
public class Tournament {
public int TournamentID { get; set; }
public String Name { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public int? SportID { get; set; }
public virtual Sport Sport { get; set; }
public virtual ICollection<Official> Officials { get; set; }
}
In the Official Entity I have this:
public class Official {
public int OfficialID { get; set; }
public String Surname { get; set; }
public String FirstName { get; set; }
public int? TournamentID { get; set; }
public virtual Tournament Tournament { get; set; }
public virtual ICollection<Match> Matches { get; set; }
}
Using some sample data and checking the SQL Server database, this works as I would expect it to. The tournament has a one-to-many relationship with officials.
The problem I'm having is that I would like the tournament to hold the primary key of an official as the head official. So I would add to the Tournament entity:
public int? OfficialID { get; set; } // foreign key to official table
public virtual Official HeadOfficial { get; set; } // navigation property
If I do this I get an attribute OfficialID and HeadOfficial_OfficialID in my Tournament table and I get TournamentID, Tournament_TournamentID and Tournament_TournamentID1 in my Officials table. I realise I now not only have a one-to-many relationship between Tournament and Official (seeing as a tournament can have many officials), but I also have a one-to-one relationship (seeing as a tournament can only have one head official).
How can I fix this problem?
You can fix the problem by giving EF a hint which navigation properties belong together. EF conventions cannot decide this anymore when you have two navigation properties in a class which refer to the same target class:
public class Tournament {
public int TournamentID { get; set; }
//...
public int? OfficialID { get; set; }
[ForeignKey("OfficialID")]
public virtual Official HeadOfficial { get; set; }
[InverseProperty("Tournament")] // the navigation property in Official class
public virtual ICollection<Official> Officials { get; set; }
}
It's also possible with Fluent API if you prefer that:
modelBuilder.Entity<Tournament>()
.HasOptional(t => t.HeadOfficial)
.WithMany()
.HasForeignKey(t => t.OfficialID);
modelBuilder.Entity<Tournament>()
.HasMany(t => t.Officials)
.WithOptional(o => o.Tournament)
.HasForeignKey(o => o.TournamentID);

ASP.NET MVC 3 and One-To-Many relationship

This is a question about Models, ASP.NET MVC 3 and relationships. I'm using the code-first approach.
Imagine this simple typical scenario of an User with its Blog Posts:
public class User
{
public virtual int UserId { get; set; }
public virtual string Nickname { get; set; }
public virtual List<Post> Posts { get; set; }
}
public class Post
{
public virtual int PostId { get; set; }
public virtual string BlogText { get; set; }
}
I made it very very simple.
Well. When I create a controller using the Controller with Read/Write actions and views using Entity Framework, the collection of Posts is not considered. It's being ignored. So, I can't get this relationship to work.
If, in place of the collection, there was a single object (public virtual string Email, for example) it works normally.
I'm asking myself and to you:
Why
How do I put references to collections in my model?
It should be a simple task, I really can't understand why it doesn't work.
Thank you.
POCO should look like below to have one-to-many relationship:
public class Post
{
public int Id { get; set; }
public string BlogText { get; set; }
public virtual User User { get; set; }
}
public class User
{
public int Id { get; set; }
public string Nickname { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}

Resources