I have some data from Facebook API and I need to store them on Azure SQL Db.
I created the models and I'm trying to set Foreign Keys to link the tables but I always have some errors.
My models:
public class FacebookDataUser
{
[Key]
[JsonProperty("id")]
public string FacebookDataUserId { get; set; }
public string name { get; set; }
public string birthday { get; set; }
public string email { get; set; }
public virtual Hometown hometown { get; set; }
public virtual Location location { get; set; }
public virtual Events events { get; set; }
public virtual Likes likes { get; set; }
public virtual Age_Range age_range { get; set; }
public string gender { get; set; }
}
public class Hometown
{
[Key]
[JsonProperty("id")]
public string HometownId { get; set; }
public string name { get; set; }
public string FacebookDataUserId { get; set; }
public FacebookDataUser FacebookDataUser { get; set; }
}
public class Location
{
[Key]
[JsonProperty("id")]
public string LocationId { get; set; }
public string name { get; set; }
public string FacebookDataUserId { get; set; }
public FacebookDataUser FacebookDataUser { get; set; }
}
public class Events
{
[Key]
public string EventsId { get; set; }
public Datum[] data { get; set; }
public string FacebookDataUserId { get; set; }
public FacebookDataUser FacebookDataUser { get; set; }
}
public class Datum
{
[Key]
public string DatumId { get; set; }
public string description { get; set; }
public string name { get; set; }
public DateTime start_time { get; set; }
public string PlaceId { get; set; }
public Place Place { get; set; }
public int attending_count { get; set; }
public string type { get; set; }
public string rsvp_status { get; set; }
public DateTime end_time { get; set; }
public string FacebookDataUserId { get; set; }
public FacebookDataUser FacebookDataUser { get; set; }
}
public class Place
{
[Key]
public string PlaceId { get; set; }
public string name { get; set; }
public string LocationEventId { get; set; }
public LocationEvent location { get; set; }
public string DatumId { get; set; }
public Datum Datum { get; set; }
}
public class LocationEvent
{
[Key]
public string LocationEventId { get; set; }
public string city { get; set; }
public string country { get; set; }
public float latitude { get; set; }
public float longitude { get; set; }
public string state { get; set; }
public string street { get; set; }
public string zip { get; set; }
public string FacebookDataUserId { get; set; }
public FacebookDataUser FacebookDataUser { get; set; }
}
public class Likes
{
// Doesn't have ID for Likes, but I need to have a Key in all classes.
// If I don't have, I get an exception
[Key]
public string LikesId { get; set; }
public Datum1[] data { get; set; }
public string FacebookDataUserId { get; set; }
public FacebookDataUser FacebookDataUser { get; set; }
}
public class Datum1
{
[Key]
public string Datum1Id { get; set; }
public string category { get; set; }
public string name { get; set; }
public int fan_count { get; set; }
public string website { get; set; }
public string LocationId { get; set; }
public LocationEvent location { get; set; }
public string[] emails { get; set; }
public string FacebookDataUserId { get; set; }
public FacebookDataUser FacebookDataUser { get; set; }
}
public class Age_Range
{
// Doesn't have ID for Age_Range, but I need to have a Key in all classes.
// If I don't have, I get an exception
[Key]
public string Age_RangeId { get; set; }
public int min { get; set; }
public string FacebookDataUserId { get; set; }
public FacebookDataUser FacebookDataUser { get; set; }
}
I get this exception:
Unable to determine the principal end of an association between the types 'ApiGroma.Models.Age_Range' and 'ApiGroma.Models.FacebookDataUser'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
If I add [Required] on Age_Range, I get this exception from Facebook API:
"modelState": {
"facebookDataUser.age_range.FacebookDataUser": [
"The FacebookDataUser field is required."
So, I tried to fill the values of Foreign Keys "by hand" before the method Add in my [HttpPost] method.
facebookDataUser.hometown.FacebookDataUserId = facebookDataUser.FacebookDataUserId;
facebookDataUser.location.FacebookDataUserId = facebookDataUser.FacebookDataUserId;
facebookDataUser.age_range.FacebookDataUserId = facebookDataUser.FacebookDataUserId;
facebookDataUser.likes.FacebookDataUserId = facebookDataUser.FacebookDataUserId;
facebookDataUser.events.FacebookDataUserId = facebookDataUser.FacebookDataUserId;
db.FacebookDataUsers.Add(facebookDataUser);
But I keep receiving the exception.
What's the proper way to do this?
It's been 2 days since I began looking for a solution, reading Microsoft blogs and others, but I can't fix this.
OBS: I am creating the database inside the context class.
Database.SetInitializer<MobileServiceContext>(new CreateDatabaseIfNotExists<MobileServiceContext>());
As I mentioned in the comments you must have your users into the database before inserting data to other tables related to those users (foreign keys).
Insert into table with foreign key
#EDIT: as promised, here is some code. I recommend you updating your table to accept null values in public virtual Hometown hometown { get; set; } and others.
public class FacebookDataUser
{
public string FacebookDataUserId { get; set; } // You already have the primary key you need
public string name { get; set; }
public string birthday { get; set; }
public string email { get; set; }
public virtual Hometown hometown { get; set; }
public virtual Location location { get; set; }
public virtual Events events { get; set; }
public virtual Likes likes { get; set; }
public virtual Age_Range age_range { get; set; }
public string gender { get; set; }
public void InsertUser(FacebookDataUser Data, Likes MoreData)
{
using (SqlConnection myCon = new SqlConnection("connection_string"))
{
using (SqlCommand query = new SqlCommand("INSERT INTO users_table (#ID, ...) VALUES (ID, ...)", myCon))
{
query.Parameters.AddWithValue("#ID", Data.FacebookDataUserId);
// add more parameters...
try
{
myCon.Open();
query.ExecuteNonQuery();
}
catch(Exception e)
{
throw e;
}
finally
{
myCon.Close();
}
}
using (SqlCommand query = new SqlCommand("INSERT INTO likes_table (..., #USERID) VALUES (..., USERID)", myCon))
{
// add more parameters...
query.Parameters.AddWithValue("#USERID", Data.FacebookDataUserId); // you won't get any exception related to the foreign key because this user is already in the parent table
try
{
myCon.Open();
query.ExecuteNonQuery();
}
catch (Exception e)
{
throw e;
}
finally
{
myCon.Close();
}
}
}
}
}
I didn't run a query to get the user ID as I mentioned because you already have it, just organizing the way you run your methods should be enough.
So, after some changes and compairing the codes, i got it working.
public class FacebookDataUser
{
[Key,JsonProperty("id")]
public string FacebookDataUserId { get; set; }
public string name { get; set; }
public string birthday { get; set; }
public string email { get; set; }
public virtual Hometown Hometown { get; set; }
public virtual Location Location { get; set; }
public virtual Events Events { get; set; }
public virtual Likes Likes { get; set; }
public virtual Age_Range Age_Range { get; set; }
public string gender { get; set; }
}
public class Hometown
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int HometownId { get; set; }
public string id { get; set; }
public string name { get; set; }
}
public class Location
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int LocationId { get; set; }
public string id { get; set; }
public string name { get; set; }
}
public class Events
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int EventsId { get; set; }
[JsonProperty("data")]
public ICollection<EventData> EventDatas { get; set; }
}
public class EventData
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int EventDataId { get; set; }
public string description { get; set; }
public string name { get; set; }
[Column(TypeName = "datetime2")]
public DateTime start_time { get; set; }
public virtual Place Place { get; set; }
public int attending_count { get; set; }
public string type { get; set; }
public string rsvp_status { get; set; }
[Column(TypeName = "datetime2")]
public DateTime end_time { get; set; }
}
public class Place
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PlaceId { get; set; }
public string id { get; set; }
public string name { get; set; }
[JsonProperty("location")]
public virtual LocationEvent LocationEvent { get; set; }
}
public class LocationEvent
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int LocationEventId { get; set; }
public string city { get; set; }
public string country { get; set; }
public float latitude { get; set; }
public float longitude { get; set; }
public string state { get; set; }
public string street { get; set; }
public string zip { get; set; }
}
public class Likes
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int LikesId { get; set; }
[JsonProperty("data")]
public virtual ICollection<LikesData> LikesData { get; set; }
}
public class LikesData
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int LikesDataId { get; set; }
public string id { get; set; }
public string category { get; set; }
public string name { get; set; }
public int fan_count { get; set; }
public string website { get; set; }
[JsonProperty("location")]
public virtual LocationEvent LocationEvent { get; set; }
[JsonProperty("emails")]
public virtual ICollection<string> emails { get; set; }
}
public class Age_Range
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Age_RangeId { get; set; }
public int min { get; set; }
}
Related
How can I use a primary key as a foreign key of another table's in two columns.
public class ResumeSharing
{
[Key]
public int ResumeSharingId { get; set; }
[ForeignKey("AppliedJobs")]
public int AppliedJobId { get; set; }
public virtual AppliedJob AppliedJobs { get; set; }
public bool OwnCompany { get; set; }
[Display(Name = "RecruiterFrom")]
public int RecruiterId { get; set; }
public virtual Recruiter Recruiters { get; set; }
[Display(Name = "RecruiterTo")]
public int RecruiterId { get; set; }
public virtual Recruiter Recruiters { get; set; }
[ForeignKey("Companies")]
public int CompanyId { get; set; }
public virtual Company Companies { get; set; }
public string SharedFiles { get; set; }
}
I want to call RecruiterId twice in this table. How can I do this?
you have to add navigation properties
public class ResumeSharing
{
[Key]
public int ResumeSharingId { get; set; }
[ForeignKey("AppliedJob")]
public int AppliedJobId { get; set; }
public virtual AppliedJob AppliedJob { get; set; }
public bool OwnCompany { get; set; }
[Display(Name = "RecruiterFrom")]
public int RecruiterFromId { get; set; }
[ForeignKey(nameof(RecruiterFromId))]
[InverseProperty("RecruiterFroms")]
public virtual Recruiter RecruiterFrom { get; set; }
[Display(Name = "RecruiterTo")]
public int RecruiterToId { get; set; }
[ForeignKey(nameof(RecruiterToId))]
[InverseProperty("RecruiterTos")]
public virtual Recruiter RecruiterTo { get; set; }
[ForeignKey("Company")]
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
public string SharedFiles { get; set; }
}
public class Recruiter
{
[Key]
public int Id { get; set; }
[InverseProperty(nameof(ResumeSharing.RecruiterFrom))]
public virtual ICollection<Recruiter> RecruiterFroms { get; set; }
[InverseProperty(nameof(ResumeSharing.RecruiterTo))]
public virtual ICollection<Recruiter> RecruiterTos { get; set; }
}
public IEnumerable<Parties> GetAll()
{
return database.Parties;
}
Works very well and the output is:
But when I Include another table by foreignkey like this:
public IEnumerable<Parties> GetAll()
{
return database.Parties.Include(i=>i.User);
}
It does not work, it returns first value of the table and nothing else,the output is :
Users.cs :
public partial class Users
{
public Users()
{
Parties = new HashSet<Parties>();
PartyParticipants = new HashSet<PartyParticipants>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Avatar { get; set; }
public string Biography { get; set; }
public string Password { get; set; }
public virtual ICollection<Parties> Parties { get; set; }
public virtual ICollection<PartyParticipants> PartyParticipants { get; set; }
}
Parties.cs :
public partial class Parties
{
public Parties()
{
Image = new HashSet<Image>();
PartyParticipants = new HashSet<PartyParticipants>();
}
public int Id { get; set; }
public string Name { get; set; }
public DateTime PartyDate { get; set; }
public DateTime CreatedDate { get; set; }
public int ParticipantCount { get; set; }
public int MaxParticipant { get; set; }
public string PartySplash { get; set; }
public string ShortDescription { get; set; }
public string Description { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public bool EntranceFree { get; set; }
public int? FreeParticipant { get; set; }
public int? FreeParticipantMax { get; set; }
public int UserId { get; set; }
public virtual Users User { get; set; }
public virtual ICollection<Image> Image { get; set; }
public virtual ICollection<PartyParticipants> PartyParticipants { get; set; }
}
As you can see on the 2nd picture it interrupts at first row of the table.
I have added this answer based on Vidmantas's comment. ReferenceLoopHandling should be ignored like this in startup.cs:
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
Hi guys I am spinning wheels on this one. I am using EF6 and ASP.Net 4.6. I have a given table which has student information and parent information. A student can have many parents and a parent can have many students. Call this table 'Contact'. I am to create a table called 'Request' which will hold information for a parent submitting a request for his student. I will create a lookup table with two columns, one for student id and one for parent id called 'StudentParents'. I want to be able to have the parent log in, select his student from a drop down of all of his students and submit the request. The many to many relationship is throwing me off as far as my include statements. How can I get EF to set up this structure so that when I GetRequest(id) I can get the Student info and the Parent info to be included? Here is my code that wont Include anything other than the request.
public class Contact
{
[Key]
public int id { get; set; }
public string student_id { get; set; }//This is the Student ID
public string last_name { get; set; }
public string first_name { get; set; }
public string middle_initial { get; set; }
public string grade { get; set; }
public int current_school_id { get; set; }
public string current_school_name { get; set; }
[Display(Name = "Parent Last Name")]
public string contact_first_name { get; set; }
[Display(Name = "Parent Middle Name")]
public string contact_middle_name { get; set; }
[Display(Name = "Parent Last Name")]
public string contact_last_name { get; set; }
public string contact_relationship { get; set; }
[Display(Name = "Parent Email")]
public string contact_email { get; set; }
[Display(Name = "Parent Address")]
public string login { get; set; }//This is the Parent ID
public string Classif_description { get; set; }
}
public class Request
{
[Key]
public int id { get; set; }
public Student student_id { get; set; }
public Contact login { get; set; }
[Display(Name = "First School Choice")]
public string firstSchool { get; set; }
[Display(Name = "Second School Choice")]
public string secSchool { get; set; }
[Display(Name = "Rising Grade")]
public string rising_grade { get; set; }
public DateTime ReqSubmitted { get; set; }
public string ReqStatus { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public string ModifBy { get; set; }
}
public class Parent
{
public int id { get; set; }
public string contact_first_name { get; set; }
public string contact_middle_name { get; set; }
public string contact_last_name { get; set; }
public string contact_relationship { get; set; }
public string contact_email { get; set; }
public string contact_address { get; set; }
public string contact_city { get; set; }
public string contact_zip { get; set; }
[Key]
public string login { get; set; }
public string contact_pw { get; set; }
public string phone { get; set; }
public string phone_type { get; set; }
public Parent() { }
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
[Key]
public int id { get; set; }
public int student_id { get; set; }
public string last_name { get; set; }
public string first_name { get; set; }
public string middle_initial { get; set; }
public DateTime birthdate { get; set; }
public string gender { get; set; }
public string grade { get; set; }
public string Fed_race_description { get; set; }
public string Classif_description { get; set; }
public int current_school_id { get; set; }
public string current_school_name { get; set; }
public int home_school_id { get; set; }
public string home_school_name { get; set; }
public Student()
{
this.Parents = new HashSet<Parent>();
}
public virtual ICollection<Parent> Parents { get; set; }
}
public class OEContext : DbContext
{
public OEContext() : base("name=OEContext")
{
}
public DbSet<Request> Requests { get; set; }
public DbSet<Parent> Parents { get; set; }
public DbSet<Contact> Contacts { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Parent>()
.HasMany(s => s.Students)
.WithMany()
.Map(x =>
{
x.MapLeftKey("login");
x.MapRightKey("student_id");
x.ToTable("StudentParents");
}
);
base.OnModelCreating(modelBuilder);
}
}
Changed the strategy. Made Request have many Contacts. So I added a constructor to the request:
public Request()
{
Contacts = new List<Contact>();
}
public virtual ICollection<Contact> Contacts { get; set; }
Next I changed the contact class:
public int ContactId { get; set; }
public Contact() { }
public virtual Request Request { get; set; }
With this relationship I can pull both Parents and a student from the Contacts associated with the Request.
my model classes first:
public class Person
{
[Required, Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string LearntSkillsAndLevelOfSkills { get; set; }
public string ProfileImage { get; set; }
public string City { get; set; }
public string PhoneNr { get; set; }
[Required]
public string Email { get; set; }
public string Hobbys { get; set; }
public string SkillsToLearn { get; set; }
public string Stand { get; set; }
public int YearsOfWorkExperience { get; set; }
public string HobbyProjectICTRelated { get; set; }
public string ExtraInfo { get; set; }
public string Summary { get; set; }
public int UserId { get; set; }
[ForeignKey("UserId")]
public virtual UserProfile profile { get; set; }
}
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public Nullable<int> ID { get; set; }
public virtual Person personprofile { get; set; }
}
when i run this however it gives me this exception: The principal end of this association must be explicitly configured
i've searched this error but it doesn't clarify it for me... so i absolutely have no clue how to fix this. Basically i want to link my Person class to the Userprofiles so that i can create a login mechanism that automatically lets 1 person who makes an account on the site get 1 Profile to Edit to his own information. He's however not allowed to modify other people their accounts.
I hope this makes my problem clear and that somebody can help me :). i'm using EF 6 btw and i get the error in the class InitializeSimpleMembershipAttribute that comes standard with the MVC example of ASP.net
Greetings and thanks in advance,
Marijn
I managed to get it working with these codes in the models:
[Table("UserProfile")]
public class UserProfile
{
[Key, DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual Person personprofile { get; set; }
}
public class Person
{
[ForeignKey("profile"), Key]
public int UserId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string LearntSkillsAndLevelOfSkills { get; set; }
public string ProfileImage { get; set; }
public string City { get; set; }
public string PhoneNr { get; set; }
[Required]
public string Email { get; set; }
public string Hobbys { get; set; }
public string SkillsToLearn { get; set; }
public string Stand { get; set; }
public int YearsOfWorkExperience { get; set; }
public string HobbyProjectICTRelated { get; set; }
public string ExtraInfo { get; set; }
public string Summary { get; set; }
public UserProfile profile { get; set; }
}
Table 1: Articles
Table 2: ArticleCategories
how do I represent the relationship between the two tables which is a 1->1 relationship:
I can do the following, but I'm not sure it's the correct way :
public class Article
{
public int ArticleIndex { get; set; }
public int Category { get; set; }
public Guid User { get; set; }
public int Parent { get; set; }
public int Level { get; set; }
public int Order { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateExpires { get; set; }
public bool Show { get; set; }
public string Title { get; set; }
public string TitleHtml { get; set; }
public string Content { get; set; }
public string ContentHtml { get; set; }
public string ShortTitle { get; set; }
public ArticleCategory Category { get; set; }
}
public class ArticleCategory
{
public int CategoryIndex { get; set; }
public string Name { get; set; }
}
By convention, Code First expects an Id property for each class/table. Then you can do something like this:
public class Article
{
public int Id { get; set; }
public int ArticleIndex { get; set; }
public int Category { get; set; }
public Guid User { get; set; }
public int Parent { get; set; }
public int Level { get; set; }
public int Order { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateExpires { get; set; }
public bool Show { get; set; }
public string Title { get; set; }
public string TitleHtml { get; set; }
public string Content { get; set; }
public string ContentHtml { get; set; }
public string ShortTitle { get; set; }
public int ArticleCategoryId { get; set; }
public virtual ArticleCategory ArticleCategory { get; set; }
}
public class ArticleCategory
{
public int Id { get; set; }
public int CategoryIndex { get; set; }
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
Note the virtual keyword. EF Code First needs this so it can perform its magic behind the scenes.
Now, if you are working with an Article, you can get all it's category info by doing article.ArticleCategory, and if you have an ArticleCategory you can find out what article it refers to with articleCategory.Articles.Single().
For more info, see this article by Scott Gu:
http://weblogs.asp.net/scottgu/archive/2010/12/08/announcing-entity-framework-code-first-ctp5-release.aspx