0

There is a Cargo class/table which has identity CargoID There is a ContainerIn class/table which containes CargoID

Every Cargo could have 1 or 0 corresponding container entries. I am trying to create navigation properties such that. Cargo.ContainerIn--->should give me associated ContainerIn entry ContainerIn.Cargo--->should give me associated Cargo entry

Cargo Class:

public class Cargo
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CargoID { get; set; }//SerialNo
    [Required]
    public DateTime DateOfPassage { get; set; }
    public string CompanyUserName { get; set; }
    public virtual ContainerIn ContainerIn { get; set; }
}

ContainerIn Subclass:

public class ContainerIn 
{
  [Key]
  [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public int ContainerInID { get; set; }
  public int CargoID { get; set; }
  public virtual Cargo Cargo { get; set; }
  public int LoadStatus { get; set; }
}

I have also tried adding public int ContainerInID { get; set; } inCargo` class. I am still getting :

`Unable to determine the principal end of an association between the types 'PisMark3.Models.Cargo.ContainerIn' and 
'PisMark3.Models.Cargo.Cargo'. 
The principal end of this association must be explicitly configured
 using either the relationship fluent API or data annotations.`

EDIT: I have added OnModelCreating in ApplicationDbContext class.

 public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<PisMark3.Models.Cargo.Cargo>()
                        .HasOptional(s => s.ContainerIn)
                        .WithRequired(ad => ad.Cargo);
        }
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
            //  Database.SetInitializer<ApplicationDbContext>(new DropCreateDatabaseIfModelChanges<ApplicationDbContext>());
        }
    .... 

Now I am getting: enter image description here

SamuraiJack
  • 5,131
  • 15
  • 89
  • 195
  • You already doing two way navigation, you just need to apply foreign key annotation. – Just code Nov 15 '18 at 13:22
  • If you have enabled lazy loading this should work automatically when you ask cargo or containerIn – Cybercop Nov 15 '18 at 13:34
  • Did the posted answer solve your issue? If not, please expand on what's happening – GregH Nov 15 '18 at 14:18
  • In EF6 you have to use the Primary Key Property as the Foreign Key Property for a 1-1 relationship. In the model you currently have a Container can have multiple ContainerIn entities, as there is nothing preventing you from setting the same CargoId on two ContainerIn entities, and so would need a ICollection Navigation Property. – David Browne - Microsoft Nov 15 '18 at 14:30
  • @Justcode `nable to determine the principal end of an association between the types 'PisMark3.Models.Cargo.ContainerIn' and 'PisMark3.Models.Cargo.Cargo'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.` – SamuraiJack Nov 16 '18 at 05:24
  • @Arbaaz please update your question with things you tried. – Just code Nov 16 '18 at 05:25
  • @Justcode updated – SamuraiJack Nov 16 '18 at 05:36

2 Answers2

3

you're pretty close. I think you want the following:

    public class Cargo
    {
      [Key]
      [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
      public int CargoID { get; set; }//SerialNo
      [Required]
      public DateTime DateOfPassage { get; set; }
      public string CompanyUserName { get; set; }
      public int ContainerInId { get; set; } //need to define a foreign key. This is happening by naming convention in this case as with your `ContainerIn.CargoId` foreign key 
      public virtual ContainerIn ContainerIn { get; set; }
    }

    public class ContainerIn 
    {
      [Key]
      [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
      public int ContainerInID { get; set; }
      public int CargoID { get; set; }
      public virtual Cargo Cargo { get; set; }
      public int LoadStatus { get; set; }
    }

Note this is a circular reference which should probably be avoided if possible however there are certainly some valid use cases. Just thought I'd give a shout out to that.

If you don't want to abide by naming conventions, you can use the ForeignKey data annotation as outlined here

GregH
  • 5,125
  • 8
  • 55
  • 109
  • I am getting `nable to determine the principal end of an association between the types 'PisMark3.Models.Cargo.ContainerIn' and 'PisMark3.Models.Cargo.Cargo'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.` – SamuraiJack Nov 16 '18 at 05:23
  • Then you need to configure teh relationship via the fluent api or data annotations as shown here: https://stackoverflow.com/questions/17254724/the-principal-end-of-this-association-must-be-explicitly-configured-using-either please see the link i referenced for more info regarding data annotations – GregH Nov 16 '18 at 13:06
0

unable to determine the principal end of an association between the types 'PisMark3.Models.Cargo.ContainerIn' and 'PisMark3.Models.Cargo.Cargo'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations

This is telling you to define your relationship, because it can not understand the relationship.

What you are looking for is One-to-Zero-or-One relationship here is the link

This is your model,

 public class Cargo
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int CargoID { get; set; }//SerialNo
        [Required]
        public DateTime DateOfPassage { get; set; }
        public string CompanyUserName { get; set; }
        public virtual ContainerIn CompanyUserNameContainIn { get; set; }
    }

    public class ContainerIn
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ContainerInID { get; set; }        
        public int LoadStatus { get; set; }        
        public int CargoID { get; set; }        
        public virtual Cargo Cargo { get; set; }
    }

This is your flent api code,

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {           
            modelBuilder.Entity<Cargo>()
                        .HasOptional(s => s.CompanyUserNameContainIn) 
                        .WithRequired(ad => ad.Cargo); 
        }

This tells entityframework that it has optional companyusername in cargo model and required model cargo in ContainerIn

You can read more in detail in the link I provided, it has nice example of student and address.

EDIT:

As you want to use identityDBContext you can modify your code as below

// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser> 
    {

        public virtual DbSet<Cargo> Cargo { get; set; }
        public virtual DbSet<ContainerIn> ContainerIn { get; set; }

        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {           
            modelBuilder.Entity<Cargo>()
                        .HasOptional(s => s.CompanyUserNameContainIn) 
                        .WithRequired(ad => ad.Cargo);

            modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
            modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
            modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });

        }

    }
Just code
  • 13,553
  • 10
  • 51
  • 93
  • Did you update your database? I see no errors trying in my project. – Just code Nov 16 '18 at 06:32
  • That's strange because I am getting the following error even when I am trying to update the database: `One or more validation errors were detected during model generation: PisMark3.Models.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType. PisMark3.Models.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType. IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.....` – SamuraiJack Nov 16 '18 at 06:51
  • I did. That is exactly when I am getting the above error in the console. – SamuraiJack Nov 16 '18 at 06:57
  • https://github.com/dholakiyaankit/One-to-Zero-or-One-relationship I added my demo project, please download it and have a look. – Just code Nov 16 '18 at 07:00
  • I think the difference is that in my project I have `ApplicationDbContext : IdentityDbContext` while you have `ApplicationDbContext : DbContext` in `IdentityModels.cs` – SamuraiJack Nov 16 '18 at 07:09
  • Check my edit basically I added inside `OnModelCreating` – Just code Nov 16 '18 at 07:19
  • :( `Not supporting creating sequence for integer types` in console on updating database – SamuraiJack Nov 16 '18 at 07:25
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/183763/discussion-between-just-code-and-arbaaz). – Just code Nov 16 '18 at 07:58