我有一个具有地址字段(地址类型)的复杂类型(宿舍),但是当我在宿舍上调试函数时,它具有地址字段= null,即使当我打开数据库浏览器时,addressID外键正确填充。
我已经确定SQL正确,但是现在不确定在哪里寻找错误
dbcontext如下,我有一个想法,这可能是问题所在
namespace OptimalHousing.Models
{
public class OptimalHousingContext : DbContext
{
public OptimalHousingContext (DbContextOptions<OptimalHousingContext> options)
: base(options)
{
}
public DbSet<OptimalHousing.Models.Dorm> Dorm { get; set; }
public DbSet<OptimalHousing.Models.Address> addresses { get; set; }
}
}
宿舍SQL
CREATE TABLE [dbo].[Dorm] (
[id] INT IDENTITY (1, 1) NOT NULL,
[addressid] INT NULL,
[dormName] NVARCHAR (MAX) NULL,
[dormUrl] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_Dorm] PRIMARY KEY CLUSTERED ([id] ASC),
CONSTRAINT [FK_Dorm_Address_addressid] FOREIGN KEY ([addressid]) REFERENCES [dbo].[Addresses] ([id])
);
GO
CREATE NONCLUSTERED INDEX [IX_Dorm_addressid]
ON [dbo].[Dorm]([addressid] ASC);
解决sql
CREATE TABLE [dbo].[addresses] (
[id] INT IDENTITY (1, 1) NOT NULL,
[street] NVARCHAR (MAX) NULL,
[streetNumber] INT NOT NULL,
[zipCode] INT NOT NULL,
[longitude] NVARCHAR (MAX) NULL,
[latitude] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_addresses] PRIMARY KEY CLUSTERED ([id] ASC)
);
我的课程:
public class Dorm
{
[Key]
public int id { get; set; }
public Dorm() {}
[DisplayFormat(NullDisplayText = "No address")]
public Address address { get; set; }
public string dormName { get; set; }
public string dormUrl { get; set; }
}
public class Address
{
[Key]
public int id { get; set; }
public string street { get; set; }
public int streetNumber { get; set; }
public int zipCode { get; set; }
public string longitude { get; set; }
public string latitude { get; set; }
}
请让我知道是否需要其他代码来解决问题
答案 0 :(得分:1)
JOIN查询不会自动发出。为此,您必须告诉EF紧急或显式加载关系。您还可以选择启用延迟加载,但这确实不建议。
渴望加载
var dorms = await _context.Dorms.Include(x => x.Address).ToListAsync();
显式加载
var dorms = await _context.Dorms.ToListAsync();
foreach (var dorm in dorms)
{
await _context.Entry(dorm).Reference(x => x.Address).LoadAsync();
}
显然,耳环加载程序效率更高,因为它将在数据库中发出真正的JOIN。显式加载将导致对列表中的每个项目进行单独的查询,但是在您希望有条件地加载或不关联的情况下很有用。
最后一个选项是延迟加载。它需要两件事:
virtual
,即public virtual Address Address { get; set; }
在UseLazyLoadingProxies()
中配置上下文时,必须通过ConfigureServices
打开延迟加载。
services.AddDbContext<OptimalHousingContext>(o =>
o.UseLazyLoadingProxies()
.UseSqlServer(Configuration.GetConnectionString("OptimalHousing")));
通过延迟加载,访问属性时,关系将被即时加载。这就是在属性上需要virtual
关键字的原因。 EF将创建一个动态代理类,该类将覆盖您的引用和集合属性,以添加一个自定义吸气剂,尝试从对象缓存中提取该吸气剂,如果失败,则发出查询以获取相关项。
但是,这效率很低,尤其是在处理事物列表时。它将针对列表中每个项目的每个关系发出单独的查询,通常会导致N + 1个查询,有时甚至会导致N(N + 1)个查询。关系越多,对象图越深,它就会变得越差。最好的选择是始终热切加载您想要使用的任何内容。