ef core shared child table with one-to-many - ef-code-first

I would like to have a shared table that can be somehow referenced to multiple parent tables. The parent tables can have multiple rows from the shared Attachement table. The Type/TypeId would be a column which points to the parent table (like if the parentId is in Person or Company table)
Shared table:
Id | ParentId | Type/TypeId | Value
1 1 Person/1 "somestringvalue"
2 1 Person/1 "another value"
3 3 Company/2 "value"
....
The models would look something like this
public class Attachement
{
[Key]
public int Id { get; set; }
//PK- Id of the parent table
public int ParentId { get; set; }
// type or enum of a parent table. Should point to which table it points to
public int Type { get; set; }
public string Value { get; set; }
}
public class Person
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
//shared table
public ICollection<Attachement> Attachements { get; set; }
}
public class Company
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
//shared table
public ICollection<Attachement> Attachements { get; set; }
}
Sidenote also - im using code first pattern.
Thanks!

Related

How to retrieve book related to a specific tag

I have 3 tables (User, Tags, Book).
In the User table I have an attribute Interesting, it has a tag_id (I saving inside it a tagid). I also have a Tags table that has many tags with many to many to book table relation.
public class Tag
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string UrlSlug { get; set; }
public virtual string Description { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
and here is the book table :
public partial class Book
{
[Key]
public int Book_id { get; set; }
[Required]
[Display(Name ="User Name")]
[StringLength(128)]
public string User_ID { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
}
and here is the user table :
public partial class AspNetUser
{
public string Id { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
[Display(Name = "Interesting")]
public int Interesting { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
What is the SQL statement here to retrieve the book that match the Interesting attribute?
For example in Interesting attribute I have 17 , so I want to retrieve the book that related to the tag id 17 ..
Note: my many-to-many table generated from the relation name is TagBooks
This should give you all the posts where it is associated with the "Swift" tag.
var books = dbContext.Books.Where(s => s.Tags.Any(f => f.Name == "Swift")).ToList();
If you want to get the result based on the TagId, change the condition in the predicate.
var books = dbContext.Books.Where(s => s.Tags.Any(f => f.Id== 17)).ToList();

Add a column to a many to many relation table code first entity framework

I have 2 classes which have a many to many relation.
public class Document
{
public int Id { get; set; }
public string Name { get; set; }
public bool AvailableOffline { get; set; }
public string URL { get; set; }
public virtual ICollection<Profile> Profiles { get; set; }
}
public class Profile
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Document> Documents { get; set; }
}
On each profile I wish to have a SortOrder field for each document. So I made the joined table explicit in another class
public class ProfileDocuments
{
[Key, Column(Order = 0)]
public int DocumentId { get; set; }
[Key, Column(Order = 1)]
public int ProfileId { get; set; }
public int SortOrder { get; set; }
[ForeignKey("DocumentId")]
public virtual Document Document { get; set; }
[ForeignKey("ProfileId")]
public virtual Profile Profile { get; set; }
}
But when I update the database the table for this last class will not have a column for SortOrder. It only holds the 2 foreign keys. How can I tell EF to generate this table with my column?
When a junction table in a many-to-many association should contain more information than just the two foreign keys, it's no longer possible to map the association as a 'pure' many-to-many (with hidden junction class).
You need an explicit class in the class model to address the extra information (as you already found out), but this also changes the association into 1-n-1:
class Document
{
...
public virtual ICollection<ProfileDocument> ProfileDocuments { get; set; }
}
class Profile
{
...
public virtual ICollection<ProfileDocument> ProfileDocuments { get; set; }
}

cannot share table no matching primary key

The entity types 'Profile' and 'Country' cannot share table 'Countries' because they are not in the same type hierarchy or do not have a valid one to one foreign key relationship with matching primary keys between them.
try removing
public int? CountryID { get; set; }
from UserProfile so it looks like this:
public class UserProfile
{
[Key]
public int UserID { get; set; }
public virtual Country Country { get; set; }
}
public class Country
{
public Country()
{
Profiles = new HashSet<UserProfile>();
}
[Key]
public int CountryID { get; set; }
public ICollection<UserProfile> Profiles { get; set; }
}
another thing : you had ICollection<Profile> instead of ICollection<UserProfile>

EF Code First with One-to-Many and Many-to-Many relationships? cause cycles or multiple cascade paths

I have four models that are Family, Mother, Father, Student, I am trying to associate Father& Mother& Student with Family table and Student table associated with Mother and Father tables. Here Family table contains information about the family. Mother and Father Tables contain their personal information, and Student table contains student information + MotherID and FatherID. Which means Family table was the Primary table to Mother and Father, Student table. MotherID of Mother table and FatherID of father table were referenced to Student table.
I am using MVC 4 Entity Framework Code First,
These are my model classes.
public class Family
{
public int FamilyID { get; set; }
public string FamilyName { get; set; }
public virtual ICollection<Mother> Mothers { get; set; }
public virtual ICollection<Father> Fathers { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Mother
{
public int MotherID { get; set; }
public int FamilyID { get; set; }
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual ICollection<Student> Students{ get; set; }
}
public class Father
{
public int FatherID { get; set; }
public int FamilyID { get; set; }
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
public int StudentID { get; set; }
public int FamilyID { get; set; }
public int MotherID { get; set; }
public int FatherID { get; set; }
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual Mother Mothers { get; set; }
public virtual Father Fathers { get; set; }
}
Database Context Class:
public class MYContext:DbContext
{
public DbSet<Family> Families { get; set; }
public DbSet<Mother> Mothers { get; set; }
public DbSet<Father> Fathers { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
//base.OnModelCreating(modelBuilder);
}
}
After writing the above code I just ran the below commands on package manager console.
PM> Add-Migration InitialContext It created an InitialContext.cs class for me.
PM> Update-Database -Verbose It give me an error below
Introducing FOREIGN KEY constraint 'FK_dbo.Student_dbo.Mother_MotherID' on table
'Student' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON
UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
What am I doing wrong??
Why I am getting this error??? Please help me some one!
What is the correct way to implement one-to-many and many-to-many relationships using EF code first? Please guide me with this example.
Try adding the [key] annotation immediately above your keys. For instance, for the student, it would look like this...
public class Student
{
[key]
public int StudentID { get; set; }
public int FamilyID { get; set; }
public int MotherID { get; set; }
public int FatherID { get; set; }
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual Mother Mothers { get; set; }
public virtual Father Fathers { get; set; }
}
This will tell you, in detail, how to manage your model from a codefirst perspective.
http://thedatafarm.com/blog/data-access/code-first-entity-framework-4-1-videos-and-articles-on-msdn/
I have found same problem and solution at Entity Framework, Code First modeling and a cyclical reference
The exception was coming from SQL Server DB not from entity framework, that table structure with the same constraints created by hand will be invalid. Foreign key properties of Mother table (Mother.FamilyID) and Father Table (Father.FamilyID), Student table (Student.MotherID) & (Student.FatherID) are not nullable, those representing required relationships and the corresponding columns in the database are also not nullable. So DB is not allowing this model.
If I remove all these properties from model classes then automatically relationship become optional because the navigation properties can be null, So DB treated as this is another model now since the FK columns in the DB can be nullable. Seemingly this is an allowed model.
It worked for me! Use nullable types as follows
Here is the solution for cause cycles or multiple cascade paths issues:
public class Student
{
public int StudentID { get; set; }
public int FamilyID { get; set; }
public int? MotherID { get; set; } //nullable types
public int? FatherID { get; set; } //nullable types
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual Mother Mothers { get; set; }
public virtual Father Fathers { get; set; }
}
Finally my model becomes with foreign key properties which represent optional instead of required relationship.
really very very thanks to # https://stackoverflow.com/users/270591/slauma and
https://stackoverflow.com/users/173937/decibyte for helping me in this type issue.

How do I build a class that shares a table with multiple columns in MVC3?

I have a Job table
public class Job
{
public int JobId { get; set; }
public int SalesManagerId { get; set; }
public int SalesRepId { get; set; }
}
and a Person table
public class Person
{
public int PersonId { get; set; }
public int FirstName { get; set; }
public int LastName { get; set; }
}
My question is, how do I link the SalesManagerId to the Person (or PersonId) as well as the SalesRepId to the Person (PersonId)? The Sales Manager and Sales Rep are independent of each other. I just don't want to make 2 different lists to support the Sales Manager and Sales Rep roles.
I'm new to MVC3, but it seems public virtual Person Person {get; set; } would be the way to go, but that doesn't work.
Any help would be appreciated!
Thanks!
Change your Job class like this
public class Job
{
public int JobId { get; set; }
public virtual Person SalesManager { set; get; }
public virtual Person SalesRep { set; get; }
}
This will create the Job table with 3 columns. JobId, SalesManager_PersonID (ForiegnKey) ,SalesRep_PersonID (Foriegn key)

Resources