I've got a basic grip of the latest version of EF code first via this tutorial - http://www.asp.net/mvc/tutorials/getting-started-with-mvc3-part4-cs but I'm slightly confused about one aspect and wondering if anybody could shed light on it? To explain - there's a class called "Site" which I want to have a field called "HomePageId" which should then map to the "SitePage" object with that Id. Seems simple enough? But when EF creates the Db and the relationships it doesn't seem to understand this. I'm sure it's something I'm doing wrong - here's the code:
public class Site
{
public int SiteId { get; set; }
public string SiteName { get; set; }
public string SiteUrlPortion { get; set; }
// Relationship - SitePages
public virtual ICollection<SitePage> SitePages { get; set; }
// Relationship - HomePage
public int HomePageId { get; set; }
public virtual SitePage HomePage { get; set; }
}
public class SitePage
{
public int SitePageId { get; set; }
public string SitePageTitle { get; set; }
public string SitePageUrlPortion { get; set; }
// Relationship - Site
public int SiteId { get; set; }
public virtual Site Site { get; set; }
}
The "SitePage" class generates the relationship back to "Site" as you would expect. But what I've got in terms of columns in both tables not only doesn't make sense but the relationship from the code-side of things doesn't work as expected. (Eg when I give the "Site" a "HomePageId" the site's "HomePage" is null.
Obviously there's little out there in terms of documentation because this is still in development, but just wondering if anybody had any ideas? Do I need to start decorating the properties with Attributes? Or am I asking it to understand something that it never will?!
Thanks to all in advance. I'll persevere anyway and post back anything I find obviously.
Rob
try marking your HomePage property with a ForeignKey attribute like this
[Foreignkey("HomePageId")]
public virtual SitePage HomePage { get; set; }
you could also use the fluent configuration but don't remember that offhand
It is probably a limitation in EF. That EF can only handle one relationship between 2 tables.
You have 2 relationships between the tables, to the list of site pages and to the home page.
try removing this line:
public virtual SitePage HomePage { get; set; }
You still have the homepageid, so in a way this information was redundant.
Related
INTRODUCTION
I am trying to learn how to use Entity framework on my own ( Code First approach ) by solving a small task that I have designed myself.
In order to understand my problem, you must be familiar with the content of the task I mentioned, so i will provide relevant information in the below section.
RELEVANT INFORMATION:
I have invented the following data model for a small quiz:
Each player answers 10 questions.
Each question has 3 possible answers, user chooses one (by clicking on the radio button, for example)
Only one answer is correct, other 2 are wrong.
PROBLEM:
I got stuck at implementing POCOs, so I need your advice on how to implement them properly.
I believe I did the basic stuff properly and that my main problem is in implementing navigational properties.
MY EFFORTS TO SOLVE THIS:
I do not have much to show. Still, my habit is to always show everything I have, in order to ease the task of the community.
Therefore, these are my unfinished POCOs:
public class Answer
{
public int AnswerId { get; set; }
public string TextOfTheAnswer { get; set; }
}
public class Question
{
public int QuestionId { get; set; }
public string TextOfTheQuestion { get; set; }
}
public class Player
{
public int PlayerId { get; set; }
public string Name { get; set; }
}
During writing of this post, I am using Google to learn as much as possible to solve my problem. If I make any headway I will update this post accordingly.
QUESTIONS:
How should I implement navigational properties to mirror the relationships from my data model?
Additionally, is there a way for me to enforce some of the imposed restrictions ( each question has 3 options; player answers on 10 different questions; only one answer is correct answer to the question; and so on...)?
I apologize if these questions may sound trivial to someone experienced. I am just beginning with C# and Entity framework, and can not wait to write anything that works. I hope you can all relate. Thank you for your understanding.
As for the navigational properties, here's something to get you started (let me know if there's something I have missed):
public class Answer
{
[Key]
public int AnswerId { get; set; }
public string TextOfTheAnswer { get; set; }
public int QuestionId{get;set;}
[ForeignKey(nameof(QuestionId))]
public virtual Question Question{get;set;}
}
public class Question
{
[Key]
public int QuestionId { get; set; }
public string TextOfTheQuestion { get; set; }
public virtual ICollection<Answer> Answers{get;set;}
public int CorrectAnswerId{get;set;}
[ForeignKey(nameof(CorrectAnswerId))]
public virtual Answer CorrectAnswer{get;set;}
}
public class SessionQuestion
{
[Key]
public int SessionQuestionId { get; set; }
public int QuestionId{get;set;}
[ForeignKey(nameof(QuestionId))]
public virtual Question Question{get;set;}
public int PlayerAnswerId{get;set;}
[ForeignKey(nameof(PlayerAnswerId))]
public virtual Answer PlayerAnswer{get;set;}
public int TriviaSessionId { get; set; }
[ForeignKey(nameof(TriviaSessionId))]
public virtual TriviaSession TriviaSession{ get; set; }
}
public class TriviaSession
{
[Key]
public int SessionId { get; set; }
public int PlayerId { get; set; }
[ForeignKey(nameof(PlayerId))]
public virtual Player Player{ get; set; }
public virtual ICollection<SessionQuestion> SessionQuestions{get;set;}
}
public class Player
{
[Key]
public int PlayerId { get; set; }
public string Name { get; set; }
public virtual ICollection<TriviaSession> TriviaSessions{get;set;}
}
Basically, EF creates subclasses of your classes at runtime, so leaving the navigation properties virtual lets the EF classes override them and obtain the reference according to the key which resides in the property whose name is the string passed to the ForeignKey attribute's constructor (quite a mouthful, huh?).
One to many navigation is easily created via declaring a virtual generic ICollection property.
Note that this model enforces the fact that only one question is correct- by design. As for the other restrictions, it sounds like business logic rules, not something you should have your data layer enforce.
I have been using NHibernate on a system for sometime and I am quite happy with how it works, but I thought I would have a go at switching NHibernate out and putting in Entity Framework purely for a learning exercise. However there is a problem I have come across though, in my domain I have 2 classes (somewhat simplified for examples)
public class Post
{
public Post()
{
Comments = new List<Comment>();
}
public virtual int Id { get; set; }
public virtual string Title { get; set; }
public virtual string Text { get; set; }
public virtual DateTime DatePosted { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public virtual int Id { get; set; }
public virtual string CommentText { get; set; }
public virtual Post Post { get; set; }
}
The mappings for this work fine when I am using NHibernate, I can quite happily traverse between my Post Comment one to many relationship, Comments are lazy loaded as expected and all is good.
But when moving to EntityFramework it seems in order for the relationship to work, I need to change my Comment class to include PostId field as well as the Post object in order to get the relationship as such.
public class Comment
{
public virtual int Id { get; set; }
public virtual string CommentText { get; set; }
public virtual int PostId { get; set; } // added in for entityframework
public virtual Post Post { get; set; }
public virtual int UserId { get; set; }
}
With this field added into my domain object the mappings now seem to work, but I feel slightly uneasy about this as it feels like Entityframework if forcing me to change my domain, and I was under the impression that the domain model should know nothing of the persistence layer.
So do I really need this extra PostId field added in to my Comment class to get the relationship to work or am I doing something wrong?
Am I just being to pedantic about the domain being affected by the change in persistence layer?
Doesn't having the Post and PostId fields together like this mean that if say you change PostId, you will also have to handle the change to update Post field or vice versa in the Comment class?
Thanks
CD
In my opinion, this is one of the major deficiencies of Entity Framework. You can get EF to work without adding the foreign key, however your application will have to retrieve the entity from the database in order to set the property because EF does not have the equivalent of NHibernate's ISession.Load method.
I am doing code first and using a Table-per-type design. I am getting the following error when I extend the second object to multiple tables:
A value shared across entities or associations is generated in more than one location. Check that mapping does not split an EntityKey to multiple store-generated columns.
My database looks like:
Thanks for the up-vote, editing to add my picture:
The POCO for the project looks like:
public abstract class Project {
public int ProjectID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
public virtual ICollection<LocationElement> LocationElements { get; set; }
public abstract string getProjectIdentifier();
}
And for a Location Element:
public enum HowObtainedCodes {
Provided = 1,
Estimated = 2,
Summarized = 3
}
public abstract class LocationElement {
public int LocationElementID { get; set; }
public int ProjectID { get; set; }
public HowObtainedCodes HowObtainedCodeID { get; set; }
}
And for a point:
[Table("ProvidedPoints")]
public class ProvidedPoint : LocationElement {
public double Lat { get; set; }
public double Long { get; set; }
public string Description { get; set; }
}
The link from projects (abstract) to scientific licences works fine, and my objects load / persist as expected. Further I can add LocationElements object in if I make it not abstract. As soon as I extend LocationElements and try to save a ProvidedPoint object I get the above message. My first thought was that the LocationElementID on ProvidedPoints was set as an Identity column, but this was not the case.
My question is: Am I doing something unexpected by trying to link two TPT objects together in this way? Am I missing something else?
As noted by #leppie above, I had to decorate the LocationElement class with the annotation [Table("LocationElements")], which immediately fixed the problem. My understanding with EF was that this was not necessary with the base table for a TPT design, and further I had not done it on the Project / ScientificLicence pair (that is, I only decorated the ScientificLicence object).
I am assuming this has something to do with the way LocationElements are added/persisted when I save a new Project object. If anyone has any additional insight I would love to know more.
Hope this helps someone else and a big thank you to leppie!
What I am trying to do is I have two tables which can be linked many to many, but the object on either side may not exist yet. Whilst this gives me chills just thinking about it, it is required for what I am working on.
I've never had to do this before with the Entity Framework Code First, I have no problem creating the many to many relationship but only when both sides exist, so I'm not 100% certain that this is even possible but hopefully someone will be able to identify how I can achieve this.
So far as entities on both sides can be optional, you can do this using third entity:
public class Entity1
{
public int Id { get; set; }
}
public class Entity2
{
public int Id { get; set; }
}
public class Many2ManyRelationEntity
{
public int Id { get; set; }
public int? Entity1Id { get; set; }
public int? Entity2Id { get; set; }
}
I have started to learn ASP.NET MVC, and at this time of studying I wanna create simple blog site. I have decided to use ASP.NET MVC and ORM Entity Framework. Probably you have some useful links about this theme?
I tried to start from creating Model code first.
i have 3 classes Post, User(User can be admin), Comments.
Please I need help to make the relations between the database models. I have code like this right now:
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<Comment> Comments { get; set; }
public DateTime PublishDate { get; set; }
}
public class User
{
public readonly bool IsAdmin { get; set; }
public string FirstName { get; set; }
public string SecondName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public DateTime DateOfBirthday { get; set; }
public string Country { get; set; }
public string City { get; set; }
public List<Post> Posts { get; set; }
public List<Comment> Comments { get; set; }
}
public class Comment
{
public int CommentId { get; set; }
public string UserName { get; set; }
public string Content { get; set; }
public DateTime PublishDate { get; set; }
}
These are my classes to create database tables, but I'm not sure how make relations like many-to-one.
Is it correct to make List of Comments for Post or just write int CommentID?? I have never use database very deep, just saw a few lessons. Can somebody to advise how make repository or correct my Model code?
Thank you very much!
There are plenty of good tutorials out there about how to do this. This one, for example:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application
To answer some of your questions, yes, the name CommentId is correct; every EF class that you want stored in the database must have either a field called Id or a field called MyClassId (where "MyClass" is the name of your class). I've found that the latter makes your life easier, especially when doing joins.
Unless you have some relationships that EF can't figure out automatically, you don't have to specify the relationships yourself: EF will automatically detect the correct relationship for you. I don't see anything in your code that EF can't handle automatically.
One thing you will have to do is make the List<Post> and List<Comment> fields virtual; that way EF can supply database-backed relationships.
Good luck.
I enjoyed the Building an MVC 3 App with Code First and Entity Framework 4.1
tutorial. Includes a video that I found very easy to follow.