我有一个带有遗留实体结构的遗留SQL Server数据库(在这种情况下我无法更改数据库或实体)
表:
公司:
Id (PK, uniqueidentifier, not null)
Name (varchar(200), not null)
地点:
Id (PK, uniqueidentifier, not null)
CompanyId (FK, uniqueidentifier, not null)
Name (varchar(200), not null)
实体:
public class Company
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Location
{
public virtual Guid Id { get; set; }
public virtual string Code { get; set; }
public virtual string Name { get; set; }
public virtual Company Company { get; set; }
}
带映射的模型:
public partial class CompanyModel : DbContext
{
public virtual DbSet<Company> Companies { get; set; }
public virtual DbSet<Location> Locations { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Location>()
.HasRequired(e => e.Company)
.WithMany()
.Map(m => m.MapKey("CompanyId"));
}
}
示例程序:
var guid = Guid.Parse("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX");
using (var mod = new CompanyModel())
{
var company = mod.Companies.FirstOrDefault(e => e.Id == guid);
var locations = company.Locations;
}
如果我现在运行此程序,则SQL跟踪会生成以下内容:
exec sp_executesql N'SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Code] AS [Code],
[Extent1].[Name] AS [Name],
[Extent1].[CompanyId] AS [CompanyId],
[Extent1].[Company_Id1] AS [Company_Id1]
FROM [dbo].[Locations] AS [Extent1]
WHERE ([Extent1].[Company_Id1] IS NOT NULL) AND ([Extent1].[Company_Id1] = @EntityKeyValue1)',N'@EntityKeyValue1 uniqueidentifier',@EntityKeyValue1='XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXX'
如您所见,包含了Company_Id1。如果我没有在OnModelCreating中映射列,我会得到Company_Id和Compan_Id1
我确定问题在于我的映射,任何帮助都会受到赞赏。
答案 0 :(得分:1)
最佳做法是在实体模型中包含FK属性。这也为外键提供了基于约定的配置。
public class Company
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; } = new HashSet<Location>();
}
public class Location
{
public Guid Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public Guid CompanyId { get; set; }
public virtual Company Company { get; set; }
}
答案 1 :(得分:1)
问题是由以下行引起的:
.WithMany()
基本上你告诉EF类似“我在Company
和Location
之间有关系,FK列名为LocationId
(但没有明确的LocationId
属性),{ {1}} Company
实体中的引用导航属性和Location
实体中的无集合导航属性。
到目前为止一切顺利。但是,当EF在Company
实体中遇到Locations
集合导航属性时,按照惯例,它会考虑另一个关系而Company
中没有引用导航属性,没有FK属性和自动生成FK列名称。这绝对不是你的意图。
根据经验,确保流畅的配置始终反映导航和FK属性的存在/不存在。在您的情况下,只需将上面的行更改为
Location
问题将得到解决。
答案 2 :(得分:0)
我会将公司模式改为:
public class Company
{
[Key] // This tells the engine that the following property id the primary key
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] // this tells the engine that the following property's value is assigned by DB
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
现在,为什么在查询中看到Company_Id1
?因为在实体框架中,这是主键的默认命名约定。您为PK使用了不同的名称,因此您需要使用[Key]
数据注释在模型中定义主键。
您的插入和更新不应指定此列的值(数据库应指定值),这就是您需要将[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
添加到模型的原因。
此外,虚拟用于导航属性(例如:外键),这就是我从公司模型中的前两个属性中删除virtual
标记的原因。
您也需要对Locations模型执行相同的操作。