How do i create One-to-One to relationship without having navigation property in dependent entity - entity-framework

I understand the following code creates "One-to-One relationship" between a principal and a dependent entity.
However, I would like to ask:
Is it possible to create one-to-one relationship without including navigation property in the dependent entity?
If yes, than how should I re-write the following code?
public class Student
{
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
[Key, ForeignKey("Student")]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}

To create a one-to-one relationship without a navigation property on the dependent side, you'll need to use the fluent API. For example, in your DbContext class, you can override OnModelCreating and use this to define the relationship:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// I'm assuming the report is optional
modelBuilder.Entity<Student>()
.HasOptional(t => t.StudentReport)
.WithRequired();
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
}
See documentation for WithRequired() here

Related

How to configure one-to-one relations to the same table in Entity Framework Core

I have a model as follows:
public class Category : BaseEntity
{
public string Name { get; set; }
public virtual Category Parent { get; set; }
public string Description { get; set; }
}
Parent property is related to the same table. How can i configure it?
I'm imagining something like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>()
.HasOne(a => a.Parent)
.OnDelete(false);
}
I'm newbie with Entity framework core, please help me !!!
Resoled by:
public class Category : BaseEntity
{
public string Name { get; set; }
public int? ParentId{ get; set; } /*added*/
[ForeignKey("ParentId")] /*added*/
public virtual Category Parent { get; set; }
public string Description { get; set; }
}

The entity type 'Program' requires a primary key to be defined

I am trying to make a simple website that tracks students, programs, and classes. I've created the entities and I'm getting an error when trying to add the migration.
"The entity type 'Program' requires a primary key to be defined."
I have tried using the [Key] attribute and there is an Id field. The other table was created just fine. What else should I try?
Here is the problem class:
public class Program
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Here is another table that I had no problems creating a migration for:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CellPhone { get; set; }
public string HomePhone { get; set; }
public string WorkPhone { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public DateTime BirthDate { get; set; }
}
Here is what is in my ApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
//public DbSet<Attendance> Attendances { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<Bill> Bills { get; set; }
//public DbSet<Session> Sessions { get; set; }
public DbSet<Program> Programs { get; set; }
}
I've commented out the other entities because I was trying to add them one at a time. Trying to add a migration with all the entities resulted in the same error with the same specific class.
Complete shot in the dark, but based on the name of this class, I'm guessing you're referencing the wrong Program. Make sure that your DbSet<Program> is actually using your Program entity and not something like the Program class used at the console app level. You'll likely need to explicitly use the namespace, i.e. DbSet<MyApp.Models.Program>.
You might also consider changing the name of the class to remove any chance of ambiguity. There's some class names that are just going to wreck havoc trying to use them because they'll conflict with framework stuff constantly. It's usually more hassle than it's worth just to have that particular name. Program is one of those.
You can try to use this way:
public class Program
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Adding [Key] attribute to the Id property.
In the file ApplicationDbContext.cs, you can override OnModelCreating method:
public DbSet<Program> Programs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Program>().ToTable("Programs").HasKey(x => x.Id);
}

Entity Framework Core multiple relationships to same table

I have a problem with two references to the same table with different columns:
public class MainApplicationContext : DbContext
{
public MainApplicationContext(MainSqlDbContext mainSqlDbContext)
{
MainSqlDbContext = mainSqlDbContext;
this.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
}
public DbSet<Organisation> Organisations { get; set; }
public DbSet<OrganisationContact> OrganisationContacts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Organisation>()
.HasKey(t => new { t.OrgId, t.OrgType, });
modelBuilder.Entity<OrganisationContact>().Property(p => p.OcsId).HasValueGenerator<SequenceNumberValueGenerator>().ValueGeneratedOnAdd();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(MainSqlDbContext.Database.GetDbConnection());
base.OnConfiguring(optionsBuilder);
}
private MainSqlDbContext MainSqlDbContext;
}
[SequenceNameAttribute("ORGANISATIONCONTACTS", "web")]
[Table("ORGANISATIONCONTACTS", Schema = "dbo")]
[Serializable]
public partial class OrganisationContact
{
[Column("OCS_ACTIVE")]
[MaxLength(1)]
public string OcsActive { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
[Column("OCS_ID")]
public int OcsId { get; set; }
[Column("OCS_NAME")]
[MaxLength(255)]
public string OcsName { get; set; }
[Column("OCS_ORGANISATION_KEY")]
[RelationshipTableAttribue("ORGANISATIONS", "dbo")]
//Relationships
public int OcsOrganisationKey { get; set; }
[ForeignKey("OcsOrganisationKey")]
public Organisation Organisation { get; set; }
[Column("OCS_TYPE")]
[MaxLength(20)]
[RelationshipTableAttribue("ORGANISATIONS", "dbo")]
// Relationships
public string OcsType { get; set; }
[ForeignKey("OCS_TYPE")]
public Organisation Organisation1 { get; set; }
public OrganisationContact()
{
}
}
[SequenceNameAttribute("ORGANISATIONS", "web")]
[Table("ORGANISATIONS", Schema = "dbo")]
[Serializable]
public partial class Organisation
{
[Column("ORG_EMAIL")]
[MaxLength(255)]
public string OrgEmail { get; set; }
[Range(0, int.MaxValue)]
[Column("ORG_ID")]
public int OrgId { get; set; }
[Required]
[Column("ORG_NAME")]
[MaxLength(255)]
public string OrgName { get; set; }
[Required]
[Column("ORG_TYPE")]
[MaxLength(20)]
public string OrgType { get; set; }
[InverseProperty("Organisation")]
public ICollection<OrganisationContact> OrganisationContacts { get; set; }
[InverseProperty("Organisation1")]
public ICollection<OrganisationContact> ORGANISATIONCONTACTS1 { get; set; }
public Organisation()
{
this.OrganisationContacts = new HashSet<OrganisationContact>();
this.ORGANISATIONCONTACTS1 = new HashSet<OrganisationContact>();
}
}
I get this error:
System.InvalidOperationException: 'The property 'OCS_TYPE' cannot be added to the type 'OrganisationContact' because there was no property type specified and there is no corresponding CLR property or field. To add a shadow state property the property type must be specified.
The core issue here is that you define a composite primary key in table Organisation but you try to use single fields as foreign keys in table OrganisationContact.
If the primary key of the referenced table is composite, the foreign keys referencing it must be composite, as well, consisting of fields of the same number and type:
[Table("ORGANISATIONCONTACTS", Schema = "dbo")]
public partial class OrganisationContact
{
// irrelevant declarations omitted for brevity...
[Column("OCS_ORGANISATION_ORG_ID")]
public int Organisation_OrgId { get; set; }
[Column("OCS_ORGANISATION_ORG_TYPE")]
public string Organisation_OrgType { get; set; }
[ForeignKey(nameof(Organisation_OrgId) + "," + nameof(Organisation_OrgType))]
public Organisation Organisation { get; set; }
[Column("OCS_ORGANISATION1_ORG_ID")]
public int Organisation1_OrgId { get; set; }
[Column("OCS_ORGANISATION1_ORG_TYPE")]
public string Organisation1_OrgType { get; set; }
[ForeignKey(nameof(Organisation1_OrgId) + "," + nameof(Organisation1_OrgType))]
public Organisation Organisation1 { get; set; }
}
[Table("ORGANISATIONS", Schema = "dbo")]
public partial class Organisation
{
// irrelevant declarations omitted for brevity...
[InverseProperty(nameof(OrganisationContact.Organisation))]
public ICollection<OrganisationContact> OrganisationContacts { get; set; }
[InverseProperty(nameof(OrganisationContact.Organisation1))]
public ICollection<OrganisationContact> ORGANISATIONCONTACTS1 { get; set; }
}
Some suggestions:
Please post MCV code. There are some exotic attributes (like RelationshipTableAttribue) and unknown type references (MainSqlDbContext) which has nothing to do with the problem but makes more cumbersome to review the issue.
Try to avoid hardcoded strings as much as possible. The nameof operator has been available for quite a while (since C# 6.0).
The preferred way to configure your DB mappings is fluent API in EF Core. Data annotation attributes are pretty limited in functionality. (E.g. you cannot define a composite primary key using attributes in EF Core.)

How do i create One-to-One mapping in EF 6 using Data Annotation approach

I am using EF 6.1.1.
I am unable to figure out how to create One-to-One relationship between two classes/tables with both entities have their owns PKs. I originally posted question link but could not get much help on it OR i am not able to get it. So, here i am putting my question in simple way.
Appreciate if someone can share thoughts on it.
My Requirement:
I would like create One-To-One relationship between Principle and Dependant with 'Id' from Principle class acts as Foreign Key in dependant class.
Principle Class
public class Student
{
public string FullName {get; set;}
}
Dependant Class
public class StudentReport
{
public string RollNumber { get; set; }
public string StudentType { get; set; }
}
Add PKs – EF requires this:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
}
Note that EF 5 and later supports naming conventions: Id indicates a primary key. Alternately, it also supports the name of the class followed by "Id", so the above keys could have been StudentId for Student and StudentReportId for StudentReport, if you wished.
Add the foreign relation as a navigation property to at least one of the tables – in this case, you stated that StudentReport is the dependent, so let's add it to that one:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
Again – by naming convention – EF determines that a single Student property on StudentReport indicates that this is a navigational property associated with a foreign key. (By defining only the Student property, but no foreign key property, you are indicating that you don't care what EF names the associated FK ... basically, you're indicating you'll always access the related Student via the property.)
If you did care about the name of the FK property, you could add it:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public int StudentId { get; set; }
public Student Student { get; set; }
}
Again – by naming convention – EF determines that StudentId is the FK associated with the Student property because it has the class name, "Student", followed by "Id".
All of this, so far, has been using conventions as defined in Entity Framework Code First Conventions, but Data Annotations are also an option, if you wish:
public class Student
{
[Key]
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
[Key]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
[ForeignKey("Student")]
public int StudentId { get; set; }
public Student Student { get; set; }
}
Doing this is actually a good idea, because it makes clearer your intent to other programmers that might not be aware of EF Conventions – but can easily infer them from simply looking at EF Data Annotations – and is still less cumbersome than Fluent API.
UPDATE
I just realized, I left this as a one-to-many, with enforcement of the one-to-one relationship being left to do in the code using this model. To enforce the one-to-one in the model, you could add a navigation property to the Student class going the other way:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
However, that's going to break, because EF doesn't know which entity to insert first on an add. To indicate which is dependent, you have to specific that the dependent class' PK is the FK to the principal class (this enforces one-to-one because – in order for a Student/StudentReport pair to be associated – their Id properties must be the exact same value):
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
[ForeignKey("Student")]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
or, using the full set of Data Annotations from earlier:
public class Student
{
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
[Key, ForeignKey("Student")]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}

Table with several one-to-many relationships

I have an EF code-first model with a table having several one-to-many relationships with other tables:
public class Note
{
[Key]
public Guid Id { get; set; }
public string NoteText { get; set; }
public string Author { get; set; }
public DateTime? CreationDate { get; set; }
}
public class Foo
{
public Foo()
{
Notes = new HashSet<Note>();
}
[Key]
public Guid Id { get; set; }
public virtual ICollection<Note> Notes { get; set; }
// other properties ommited...
}
public class Bar
{
public Bar()
{
Notes = new HashSet<Note>();
}
[Key]
public Guid Id { get; set; }
public virtual ICollection<Note> Notes { get; set; }
// other properties ommited...
}
As you can see, both Foo and Bar have their own list of Notes, but a Note belongs to either a Foo or a Bar.
When scaffolding the migration, EF creates a foreign key for Foo and Bar in the Notes table, which I think is not correct. I would like, instead, that a link table is created between Foo and Notes and another one between Bar and Notes.
Is there a way to automatically do this? Or do I have to manually create these classes in my code-first implementation?
This has already been answered in this other post!
But to save you a little googling, you are getting a one-to-many association, which is correct. you want a many-to-many relationship in your code, so what you will need to do is :
in your Notes class:
public class Note
{
[Key]
public Guid Id { get; set; }
public string NoteText { get; set; }
public string Author { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? CreationDate { get; set; }
public virtual ICollection<Foo> Foos { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
Hope this helps