简体   繁体   中英

Entity Framework CodeFirst many to many return object null

i have problem with fluent api and entity framework (relation many to many). When i trying get data from database a have null value on object Company and pkdClassification . Value CompanyId and PkdClassyficationId returns properly.

context

 //in contrstructor set 
 // this.Configuration.LazyLoadingEnabled = true;

      .Entity<CompanyPkdClassification>()
      (c => new { c.PkdClassyficationId, c.CompanyId });

         modelBuilder.Entity<Company>()
            .HasMany(c => c.companyPkdClassification)
            .WithRequired()
            .HasForeignKey(c => c.CompanyId);

         modelBuilder.Entity<PkdClassification>()
            .HasMany(c => c.companyPkdClassification)
            .WithRequired()
            .HasForeignKey(c => c.PkdClassyficationId);}

pkdClassification

public class PkdClassification 
{
    [Key]
    [DisplayName("Id")]
    public int id { get; set; }
   ...
    public virtual ICollection<CompanyPkdClassification> companyPkdClassification { get; set; }
}

companyPkdClassification

public class CompanyPkdClassification 
{
    [ForeignKey("company")]
    public int CompanyId { get; set; }

    [ForeignKey("pkdClassification")]
    public int PkdClassyficationId { get; set; }

    public virtual ICollection<Company> company { get; set; }
    public virtual ICollection<PkdClassification> pkdClassification { get; set; }
}

and last one company

public class Company : baseModel
{
   ... 
virtual ICollection<CompanyPkdClassification> companyPkdClassification { get; set; }


}

The best way to map a many-to-many relationship in Code First is this:

public class Classification 
{
  [Key]
  [DisplayName("Id")]
  public int id { get; set; }
  ...
  public virtual ICollection<Company> Companies{ get; set; }
}

public class Company
{
  public int Id { get; set; }
  ... 
  public virtual ICollection<Classification> Classifications { get; set; }
}

By default Code-First will create a third joining table, ClassificationCompanies which will consist PK of both the tables ie. ClassificationId & CompanyId .

If you need to specify the name of the junction table and the FK columns, then you could configure the relationship overriding the OnModelCreating method on your context an use Fluent Api:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{

   modelBuilder.Entity<Classification>()
               .HasMany<Company>(s => s.Companies)
               .WithMany(c => c.Classifications)
               .Map(cs =>
                        {
                            cs.MapLeftKey("ClassificationId");
                            cs.MapRightKey("CompanyId");
                            cs.ToTable("ClassificationCourses");
                        });

}

Another way is create an entity that represent the junction table (as you trying to do) and stablish two one-to-many relationships with Classification and Company , but if you don't need to add extra columns to the junction table, It's recommended use the first variant. If you follow this variant, the entity that represent the junction table would be like this:

public class CompanyPkdClassification 
{
   public int CompanyId { get; set; }

   public int PkdClassyficationId { get; set; }

   public virtual Company Company { get; set; }
   public virtual Classification Classification { get; set; }
}

And the configuration:

     modelBuilder.Entity<CompanyPkdClassification>().HasKey(c => new { c.PkdClassyficationId, c.CompanyId });

     modelBuilder.Entity<Company>()
        .HasMany(c => c.companyPkdClassification)
        .WithRequired(cc=>Company)
        .HasForeignKey(c => c.CompanyId);

     modelBuilder.Entity<PkdClassification>()
        .HasMany(c => c.companyPkdClassification)
        .WithRequired(cc=>Classification)
        .HasForeignKey(c => c.PkdClassyficationId);}

Could you show the query that you are using to get the values? I think it will be related to the objects being lazy loaded. If you do ToList() before requesting the navigation property then these values will be null. You have to either force the value to be included by adding this in your Query:

.Include(x => x.Company)

and so on for each object you want or request the value while the object is still live. ie before you do a ToList(); Explained in more detail here: https://msdn.microsoft.com/en-gb/library/vstudio/bb738633%28v=vs.100%29.aspx

Based on your comment below FirstOrDefault() will execute the query so can no longer populate the navigation properties after this point. I would try this (Providing dbContext.company is a set of Company objects):

Add using for System.Data.Entity;

public Company getCompany(int id) { 
    Company data = dbContext.company.Include(x => x.companyPkdClassification .Select(y => y.company)).Include(x => x.companyPkdClassification .Select(y => y.pkdClassification)).Where(i => i.id == id).FirstOrDefault();
    return data; 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM