Is there anyway to set the relationship of many tables from Model? - c#

I want to set the relationship of some tables and make some columns in the table can be null.
[Table("tbl_useraccount")]
public class AccountViewModels
{
[Key]
public string AccountId { get; set; }
public string Email { get; set; }
public string HashPassword { get; set; }
}
and here is the table which I want to make relationship:
[Table("tbl_userprofile")]
public class UserProfileViewModels
{
[Key]
public int Id { get; set; }
public string AccountId { get; set; }
public string Address { get; set; }
public int PhoneNumber { get; set; }
}
My question is: How to set AccountId (in the table tbl_useraccount) is the primary key and as the foreign key in the table tbl_userprofile from Model?
And my sub-question is: Is it necessary to set NULL or NOT NULL for per column name? If it is necessary, how can I do that?
p/s: I'm using MVC 5 and SQL Server.

First remark I have is that you don't use viewmodels for your database generation. ViewModels are only used for your views.
To create a relationship, you should add the AccountModel to the UserProfile, I added virtual to enable lazy loading. Also add the ForeignKey data annotation to the extra property you want to map your key to (optional)
[Table("tbl_useraccount")]
public class AccountModel
{
[Key]
public string AccountId { get; set; }
public string Email { get; set; }
public string HashPassword { get; set; }
}
[Table("tbl_userprofile")]
public class UserProfileModels
{
[Key]
public int Id { get; set; }
public string AccountId { get; set; }
public string Address { get; set; }
[ForeignKey("AccountModel")]
public int PhoneNumber { get; set; }
public virtual AccountModel AccountModel { get; set;}
}
If you want a field not to be null, if this is even possible. Use the [Required] data annotation. "Public int PhoneNumber" can not be null, you'll have to write it as following: "Public int? PhoneNumber".

Related

Require One of Multiple Foreign Keys in Entity Framework

I'm basically trying to enforce this in Entity Framework: Require Only One Of Multiple Columns Be Not Null
My database has several 1:m relationships where the child entity belongs to one of several parent entities. For example, let's say I have tables for Teachers, Students, and Guardians. Each of those can have many PhoneNumbers and EmailAddresses. I am using EF Code First, and my models look something like:
public class Teacher {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class Student {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class Guardian {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class PhoneNumber {
public int Id { get; set; }
public string Number { get; set; }
}
public class EmailAddress {
public int Id { get; set; }
public string Email { get; set; }
}
When I run the migration, this creates the database with the tables/columns I would expect. The PhoneNumbers and EmailAddresses tables each have columns Teacher_Id, Student_Id, and Guardian_Id, which are foreign keys to their respective parent entity. However, there are no constraints on how many parent entities can be set on the child. For example, I can create a PhoneNumber that has all three parent IDs set to null, or I can set both a Teacher_Id and a Guardian_Id.
I tried adding a required attribute to the parents like so:
public class Teacher { // Also Student/Guardian
public int Id { get; set; }
public string Name { get; set; }
[Required]
public List<PhoneNumber> PhoneNumbers { get; set; }
[Required]
public List<EmailAddress> EmailAddresses { get; set; }
}
That does not seem to have any effect.
I think there is no way to do this on entities. Instead, create a migration and try to alter the table in migration class like this:
public partial class YourMigrationName: Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("ALTER TABLE [dbo].[PhoneNumber]
WITH CHECK ADD CONSTRAINT [CK_PhoneNumer_Teacher_Student_Guardian] CHECK (Teacher_Id
is not null or Student_Id is not null or Guardian_Id is not null)
GO
ALTER TABLE [dbo].[EmailAddress] WITH CHECK ADD CONSTRAINT
[CK_EmailAddress_Teacher_Student_Guardian] CHECK (Teacher_Id is not null or
Student_Id is not null or Guardian_Id is not null)
");
}
}
Try this:
public class PhoneNumber
{
public int Id { get; set; }
public string Number { get; set; }
//Added this code:
[Required]
public Teacher Teacher { get; set;}
}
public class EmailAddress {
public int Id { get; set; }
public string Email { get; set; }
//Added this code:
[Required]
public Teacher Teacher { get; set;}
}
That would make sure you cannot create PhoneNumber without Teacher. You can also do this:
public class PhoneNumber
{
public int Id { get; set; }
public string Number { get; set; }
public int TeacherId
public Teacher Teacher { get; set;}
}
That would also detect that you want to add constraint on your PhoneNumber. Both ways work fine.

Problem with One To One Relation EF6 and primary key

I have 3 tables
User > Employee > Operator
There is a one to one relation on each other's end
public class User
{
[Key]
public int Id { get; set; }
public string Username { get; set; }
public DateTime? LoginDate { get; set; }
public bool IsActive{ get; set; }
public ICollection<Role> Roles { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
[Key]
[ForeignKey("User")]
public int Id { get; set; }
public string Name{ get; set; }
public string Email { get; set; }
public int UserId { get;set; }
public virtual User User { get; set; }
public virtual Operator Operator{ get; set; }
}
public class Operator
{
[Key]
[ForeignKey("Employee")]
public int Id { get; set; }
public int EmployeeId {get;set;}
public EmployeeEmployee{ get; set; }
}
However this does create the one to one relation when i create a diagram in Sql Server MS to check the relations.
Problem is, when I'm just trying to insert data directly graphically from Sql it expects me to insert the primary key on Employee and Operator tables. Why aren't they automatic like the User one?
First, you don't need specify two variables to store same informations.
public int UserId { get;set; }
public int EmployeeId {get;set;}
already stored in Id. Not need to duplicate it.
Foreign keys doesn't use identity (doesn't generate values). So you need create User and then create an Employe where set the "User" property with user created before. (Main idea is that you need initialise reference to foreign key manually)
User user = new User{...};
Employee employe = new Employee{User = user, ...};
context.Add(employee);
context.SaveChanges();
Or maybe you will use hierarchy. (I don`t checked on 3 level, but on 2 this works perfectly).
public class User
{
[Key]
public int Id { get; set; }
public string Username { get; set; }
public DateTime? LoginDate { get; set; }
public bool IsActive{ get; set; }
public ICollection<Role> Roles { get; set; }
}
public class Employee : User
{
public string Name{ get; set; }
public string Email { get; set; }
}
public class Operator : Employee
{
}

Entity framework Code First One-to-One relationship

I have two entities which I want to be connected 1:1 relationship. User is principal and UserActivation is dependent, but I have no idea how that works.
public class User
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public virtual UserActivation UserActivation { get; set; }
}
public class UserActivation
{
[Key]
public Guid Id { get; set; }
public Guid UserId { get; set; }
public bool Active { get; set; }
public virtual User User { get; set; }
}
I have tried to remove 'virtual' keyword, have tried to add ForeignKey("UserId") or ForeignKey("User"), I've even tried to make [Key, ForeignKey("User") and none of them helped me. I want to make 1:1 relationship using only dataannotations. Any help is really appreciated. Also my both classes has their own PKs.
Foreign keys are not supported for 1:1 try:
public class User
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public virtual UserActivation UserActivation { get; set; }
}
public class UserActivation
{
[Key]
[ForeignKey("User")]
public Guid Id { get; set; }
public bool Active { get; set; }
public virtual User User { get; set; }
}
Unable to determine the principal end of an association between the types ‘Model.PersonPhoto’ and ‘Model.Person’. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Julie Lehrman discusses this in her Code First book:
"This problem is most easily solved by using a ForeignKey annotation
on the dependent class to identify that it contains the foreign key.
When configuring one-to-one relationships, Entity Framework requires
that the primary key of the dependent also be the foreign key. In our
case PersonPhoto is the dependent and its key, PersonPhoto.PersonId,
should also be the foreign key. Go ahead and add in the ForeignKey
annotation to the PersonPhoto.PersonId property, as shown in Example
4-21. Remember to specify the navigation property for the relationship
when adding the ForeignKey annotation."
This post is quite old so I thought I'd post the EF 6 solution
Try this...
public class User
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public virtual UserActivation UserActivation { get; set; }
}
public class UserActivation
{
[ForeignKey("User")]
public Guid Id { get; set; }
public Guid UserId { get; set; }
public bool Active { get; set; }
public virtual User User { get; set; }
}

EF6, Composite Key, is annotation enough? Or Do I have to also use Fluent API?

I have 3 entities:
public class AspNetUser
{
public string Id {get; set;}
}
public class Event
{
public int Id {get; set;}
}
public class UserEvent
{
[Column(Order=0), Key, ForeignKey("AspNetUsers")]
public string UserId { get; set; }
[Column(Order=1), Key, ForeignKey("Events")]
public int EventId { get; set; }
public DateTime EnrolTime { get; set; }
public virtual AspNetUser User { get; set; }
public virtual Event Event { get; set; }
}
As you can see that, the UserEvent is just a relationship table which has both UserId and EventId from 2 tables.
My question is:
Is annotation enough to tell EF to create the 2 foreign keys? Or I have to also use Fluent API to do it in the OnModelCreating() method in the DbContext class? Or I have to create a configuration class to do so?
I saw something in this post(it makes me confused):
Entity Framework Multiple Column as Primary Key by Fluent Api
ForeignKey("X")
I guess the X should be the table name rather than the entity's name, right?
E.g. X should be the AspNetUsers(which is in the database), rather than AspNetUser which is the entity name.
Thank you.
Yes, it's enough using Data Annotations, but the problem is you need to specify in the ForeignKey attribute the name of navigation property`that represents the relationship it is a foreign key for:
public class UserEvent
{
[ Key,Column(Order=0), ForeignKey("User")]
public string UserId { get; set; }
[ Key,Column(Order=1), ForeignKey("Event")]
public int EventId { get; set; }
public DateTime EnrolTime { get; set; }
public virtual AspNetUser User { get; set; }
public virtual Event Event { get; set; }
}
Alternatively, you can apply the ForeignKey annotation to the navigation property and tell it which property is the foreign key for the relationship:
public class UserEvent
{
[Key,Column(Order=0)]
public string UserId { get; set; }
[Key,Column(Order=1)]
public int EventId { get; set; }
public DateTime EnrolTime { get; set; }
[ForeignKey("UserId")]
public virtual AspNetUser User { get; set; }
[ForeignKey("EventId")]
public virtual Event Event { get; set; }
}
public class UserEvent
{
public DateTime EnrolTime { get; set; }
public string UserId { get; set; }
[ForeignKey("UserId")]
public virtual AspNetUser User { get; set; }
public int EventId { get; set; }
[ForeignKey("EventId")]
public virtual Event Event { get; set; }
}

Entity Framework 5 Code First Relationships

I'm having trouble understanding how to create relationships between classes on a project that I'm building.
I have a class Photo that has a required one-to-one relationship with PhotoExif, and Photo has an optional one-to-one relationship with FeaturedPhoto.
I'm getting the error:
Unable to determine composite primary key ordering for type Website.Models.PhotoExif. Use the ColumnAttribute or the HasKey method to specify an order for composite primary keys.
Help would be much appreciated.
Photo.cs
public class Photo
{
[Key]
public int PhotoID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public Orientation Orientation { get; set; }
public int Rating { get; set; }
public string URL { get; set; }
public string Filename { get; set; }
public DateTime DateAdded { get; set; }
public bool Hide { get; set; }
public string MetaDescription { get; set; }
public string MetaKeywords { get; set; }
public virtual PhotoExif PhotoExif { get; set; }
}
PhotoExif.cs
public class PhotoExif
{
[Key]
public int PhotoExifID { get; set; }
public int PhotoID { get; set; }
public string ShutterSpeed { get; set; }
public string Aperture { get; set; }
public string FocalLength { get; set; }
public int ISO { get; set; }
public string ExposureBias { get; set; }
public bool Flash { get; set; }
public string WhiteBalance { get; set; }
public string Lens { get; set; }
public DateTime DateTaken { get; set; }
public float Longitude { get; set; }
public float Latitude { get; set; }
public int Zoom { get; set; }
public string Location { get; set; }
public virtual Photo Photo { get; set; }
}
FeaturedPhoto.cs
public class FeaturedPhoto
{
[Key]
public int FeaturedPhotoID { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public string InformationLocation { get; set; }
public string ImagePosition { get; set; }
public virtual Photo Photo { get; set; }
}
As per the error message:
Use the ColumnAttribute or the HasKey method to specify an order for
composite primary keys.
you need to add [Column(Order="#")] annotations to PhotoID and PhotoExifID properties of the PhotoExif table.
To me it looks that you don't want a composite primary key on PhotoExif. I don't know why EF tries to infer a composite key, but the reason is possibly 1) that the Photo property has the PhotoID property as foreign key by convention, 2) in a one-to-one relationship the foreign key must be identical with the primary key, 3) there is another property PhotoExifID you have marked a key. So, maybe, EF assumes that this marked key plus the infered key from the one-to-one relationship form a composite key together. (This behaviour would be pretty strange, but I can't see how your model and your annotations could lead to this exception about composite key ordering.)
Anyway, the PhotoID property doesn't seem right, because in a one-to-one relationship principal and dependent must share the same primary key and the FK of the dependent is the PK at the same time. I would try to remove this property and add a FK attribute:
public class PhotoExif
{
[Key]
public int PhotoExifID { get; set; }
public string ShutterSpeed { get; set; }
//...
[ForeignKey("PhotoExifID")]
public virtual Photo Photo { get; set; }
}
Similarly you must define the FK for FeaturedPhoto, otherwise EF cannot determine what's the principal and what's the dependent of the relationship. Depending on the details of the relationships - are they required-required, required-optional or optional-optional and which entity is principal and which one is dependent? - it might be necessary to define the mapping with Fluent API since data annotations do not support every mapping option that Fluent API does.

Categories

Resources