我有以下型号-Person
和Address
。
Person
可以存在而没有一个Address
Address
始终属于Person
班级:
public class Person {
// properties
[ForeignKey("Address")]
public int? AddressId { get; set; }
public virtual Address Address { get; set; }
}
public class Address {
// properties
[ForeignKey("Person")]
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
人员配置:
HasOptional(a => a.Address)
.WithMany()
.HasForeignKey(u => u.AddressId);
地址配置:
HasRequired(a => a.Person)
.WithMany()
.HasForeignKey(u => u.PersonId);
问题
SSMS显示所有FK和约束均符合预期。但是,当我执行以下操作时:
var dbPerson = db.Persons.Include(s => s.Address).ToList();
Person
返回的对象(具有地址的对象)都没有Address
或没有AddressId
填充。一切都为空。
当对进行相同操作时db.Address
,我将按预期填充所有属性-完整的有效关系。是什么导致我的1:1可选关系的主要结尾不拉入从属实体?
我应该注意,我确实需要如上所述在两个实体上都可以访问的FK ID。
让我告诉您,“一对一” /“可选”关系不是这样构成的。我正在分享代码,以建立1:1/0关系。另外,当您使用流畅的API时,无需使用数据注释属性。只使用其中之一,流利的API更好,因为关系看起来很清楚。
在1:1/0关系中,未单独定义外键。外键仅在任何一个表中定义,一个实体的主键成为另一相关实体的主键和外键。在此示例中,我将ID字段用作Person实体(表)的主键,并将ID用作Address实体(表)的主键和外键。这是1:1/0关系的正确方法。如果我们不遵守这一约定,则这种关系将无法正确建立并面临问题。
这是代码
public class Person
{
// properties
public int Id { get; set; }
public string Name { get; set; }
public virtual Address Address { get; set; }
}
public class Address
{
// properties
public int Id { get; set; }
public string Location { get; set; }
public virtual Person Person { get; set; }
}
public class PersonConfiguration : EntityTypeConfiguration<Person>
{
public PersonConfiguration()
{
ToTable("Person");
HasKey(p => p.Id);
}
}
public class AddressConfiguration : EntityTypeConfiguration<Address>
{
public AddressConfiguration()
{
ToTable("Address");
HasKey(p => p.Id);
Property(a => a.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
HasRequired(p => p.Person)
.WithOptional(a => a.Address);
}
}
public class AppObjectContext : DbContext
{
public AppObjectContext() : base("AppConnectionString")
{
}
public DbSet<Person> People { get; set; }
public DbSet<Address> Addresses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new PersonConfiguration());
modelBuilder.Configurations.Add(new AddressConfiguration());
}
}
这是结果截图
在屏幕快照中,您可以看到,由于映射关系,我们可以从Person实例访问Address实例,并从Address实例访问Person实例。
这是我放在表中的数据。
这是表格结构
人员表SQL脚本
CREATE TABLE [dbo].[Person](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
CONSTRAINT [PK_dbo.Person] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
地址表SQL脚本
CREATE TABLE [dbo].[Address](
[Id] [int] NOT NULL,
[Location] [nvarchar](max) NULL,
CONSTRAINT [PK_dbo.Address] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[Address] WITH CHECK ADD CONSTRAINT [FK_dbo.Address_dbo.Person_Id] FOREIGN KEY([Id])
REFERENCES [dbo].[Person] ([Id])
GO
ALTER TABLE [dbo].[Address] CHECK CONSTRAINT [FK_dbo.Address_dbo.Person_Id]
GO
回应您的注意事项:
我应该注意,我确实需要在上述两个实体上都可以访问的FK ID。
它违反了1:1/0关系的约定,但是更好的方法如下。
在一对一关系中,外键和主键的值相同,这意味着,如果访问一个实体的主键实体,则它也是另一实体的外键和主键。
例如,如果人员的主键为20,则与该人员映射的地址的外键和主键也为20。这是正确的访问方式。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句