EF6:多对多关系返回空集合
EF6: Many-to-many relationship returning empty collections
过去 3 个小时我一直在努力解决这个问题,我确信我遗漏了一些非常明显的东西...
型号代码如下:
[Table("company")]
public partial class company
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public company()
{
job = new HashSet<job>();
contact = new HashSet<contact>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int companyId { get; set; }
[Required]
[StringLength(255)]
public string name { get; set; }
[StringLength(255)]
public string address { get; set; }
[StringLength(255)]
public string locality { get; set; }
[StringLength(255)]
public string city { get; set; }
[StringLength(100)]
public string state { get; set; }
[StringLength(16)]
public string postalCode { get; set; }
[StringLength(2)]
public string country { get; set; }
[StringLength(16)]
public string phone { get; set; }
[StringLength(63)]
public string email { get; set; }
[StringLength(127)]
public string website { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<job> job { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<contact> contact { get; set; }
}
[Table("contact")]
public partial class contact
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public contact()
{
this.company = new HashSet<company>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int contactId { get; set; }
[Required]
[StringLength(64)]
public string firstName { get; set; }
[Required]
[StringLength(64)]
public string lastName { get; set; }
[StringLength(1)]
public string middleInitial { get; set; }
public string title { get; set; }
[StringLength(18)]
public string phoneNumber { get; set; }
[StringLength(128)]
public string emailAddress { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<company> company { get; set; }
}
[Table("job")]
public class job
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public job()
{
company = new HashSet<company>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int jobId { get; set; }
public string jobTitle { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<company> company { get; set; }
}
在 OnModelCreating
我有这个:
modelBuilder.Entity<company>()
.HasMany(e => e.job)
.WithMany(e => e.company)
.Map(m => m.ToTable("company_job", "dbo").MapLeftKey("companyId").MapRightKey("jobId"));
modelBuilder.Entity<company>()
.HasMany(e => e.contact)
.WithMany(e => e.company)
.Map(m => m.ToTable("company_contact", "dbo").MapLeftKey("companyId").MapRightKey("contactId"));
我已经在数据库端检查了以下所有内容:
- 所有三个主要 table 都存在并且与模型逐列匹配。
- 桥 table 的所有外键关系都存在。
- 两个桥 table 都有一个由两列组成的复合主键。
- 两个桥 table 的名称都与
Map
方法参数相匹配,桥 table 中的列也是如此。
- 数据库中有适当的数据,应该会导致
job
和 contact
个实体出现在所有 company
个实体下。
- 手动写入数据库查询确实成功生成了预期的数据。
但是:
ctx.company.Where(x => x.companyId == 300).job.Count()
总是returns0
。正在尝试:
ctx.company.Where(x => x.companyId == 300).job.FirstOrDefault()
returns null
.
我尝试在上下文中设置日志记录:
Database.Log = msg => System.Diagnostics.Debug.WriteLine(msg);
而且我注意到发送到数据库的唯一查询是针对 company
table。它不执行连接查询。它甚至从未触及 job
或 contact
table 或桥 table。它只是使用正确的 WHERE
子句对 company
table 进行一次查询,但不会再进一步。
为了好玩,我尝试颠倒 .Map
调用中字段的顺序,但没有效果。 (换句话说:.Map(m => m.ToTable("company_job", "dbo").MapLeftKey("jobId").MapRightKey("companyId"))
没有改变。)
好的,我错过了什么?
确认...
在上下文构造函数中是这样的:
base.Configuration.ProxyCreationEnabled = false;
我删除了它,现在它似乎可以工作了!
(我继承了这段代码,所以这里的教训是:永远不要假设你继承的代码完全按照你认为的那样做!)
过去 3 个小时我一直在努力解决这个问题,我确信我遗漏了一些非常明显的东西...
型号代码如下:
[Table("company")]
public partial class company
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public company()
{
job = new HashSet<job>();
contact = new HashSet<contact>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int companyId { get; set; }
[Required]
[StringLength(255)]
public string name { get; set; }
[StringLength(255)]
public string address { get; set; }
[StringLength(255)]
public string locality { get; set; }
[StringLength(255)]
public string city { get; set; }
[StringLength(100)]
public string state { get; set; }
[StringLength(16)]
public string postalCode { get; set; }
[StringLength(2)]
public string country { get; set; }
[StringLength(16)]
public string phone { get; set; }
[StringLength(63)]
public string email { get; set; }
[StringLength(127)]
public string website { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<job> job { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<contact> contact { get; set; }
}
[Table("contact")]
public partial class contact
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public contact()
{
this.company = new HashSet<company>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int contactId { get; set; }
[Required]
[StringLength(64)]
public string firstName { get; set; }
[Required]
[StringLength(64)]
public string lastName { get; set; }
[StringLength(1)]
public string middleInitial { get; set; }
public string title { get; set; }
[StringLength(18)]
public string phoneNumber { get; set; }
[StringLength(128)]
public string emailAddress { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<company> company { get; set; }
}
[Table("job")]
public class job
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public job()
{
company = new HashSet<company>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int jobId { get; set; }
public string jobTitle { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<company> company { get; set; }
}
在 OnModelCreating
我有这个:
modelBuilder.Entity<company>()
.HasMany(e => e.job)
.WithMany(e => e.company)
.Map(m => m.ToTable("company_job", "dbo").MapLeftKey("companyId").MapRightKey("jobId"));
modelBuilder.Entity<company>()
.HasMany(e => e.contact)
.WithMany(e => e.company)
.Map(m => m.ToTable("company_contact", "dbo").MapLeftKey("companyId").MapRightKey("contactId"));
我已经在数据库端检查了以下所有内容:
- 所有三个主要 table 都存在并且与模型逐列匹配。
- 桥 table 的所有外键关系都存在。
- 两个桥 table 都有一个由两列组成的复合主键。
- 两个桥 table 的名称都与
Map
方法参数相匹配,桥 table 中的列也是如此。 - 数据库中有适当的数据,应该会导致
job
和contact
个实体出现在所有company
个实体下。 - 手动写入数据库查询确实成功生成了预期的数据。
但是:
ctx.company.Where(x => x.companyId == 300).job.Count()
总是returns0
。正在尝试:
ctx.company.Where(x => x.companyId == 300).job.FirstOrDefault()
returns null
.
我尝试在上下文中设置日志记录:
Database.Log = msg => System.Diagnostics.Debug.WriteLine(msg);
而且我注意到发送到数据库的唯一查询是针对 company
table。它不执行连接查询。它甚至从未触及 job
或 contact
table 或桥 table。它只是使用正确的 WHERE
子句对 company
table 进行一次查询,但不会再进一步。
为了好玩,我尝试颠倒 .Map
调用中字段的顺序,但没有效果。 (换句话说:.Map(m => m.ToTable("company_job", "dbo").MapLeftKey("jobId").MapRightKey("companyId"))
没有改变。)
好的,我错过了什么?
确认...
在上下文构造函数中是这样的:
base.Configuration.ProxyCreationEnabled = false;
我删除了它,现在它似乎可以工作了!
(我继承了这段代码,所以这里的教训是:永远不要假设你继承的代码完全按照你认为的那样做!)