如何使用外键正确检索数据对象的虚拟属性?
How can I properly retrieve the virtual properties of my Data object with foreign keys?
我正在尝试完成这项工作:
namespace DataService.Domain {
public class Death {
[StringLength(10, MinimumLength = 10)]
public string PersonId { get; set; }
[StringLength(4, MinimumLength = 4)]
public string DeathYear { get; set; }
[NotMapped]
public virtual Person Person { get; set; }
}
}
namespace DataService.Domain {
public class Work {
[StringLength(10, MinimumLength = 10)]
public string TitleId { get; set; }
[StringLength(10, MinimumLength = 10)]
public string PersonId { get; set; }
[StringLength(100, MinimumLength = 1)]
public string Job { get; set; }
[NotMapped]
public virtual Title Title { get; set; }
[NotMapped]
public virtual Person Person { get; set; }
}
}
namespace DataService.Domain {
public class Person {
public Person() {
Works = new HashSet<Work>();
}
[StringLength(10, MinimumLength = 10)]
public string Id { get; set; }
[StringLength(100, MinimumLength = 1)]
public string LastName { get; set; }
[StringLength(100, MinimumLength = 1)]
public string FirstName { get; set; }
[StringLength(4, MinimumLength = 4)]
public string BirthYear { get; set; }
[NotMapped]
public virtual ICollection<Work> Works { get; set; }
#nullable enable
[NotMapped]
public virtual Death? Death { get; set; }
#nullable disable
}
}
namespace DataService {
public class DataContext: DbContext {
public DbSet<Person> Persons { get; set; }
public DbSet<Death> Deaths { get; set; }
public DbSet<Work> Works { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
base.OnConfiguring(optionsBuilder);
optionsBuilder.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information);
optionsBuilder.EnableSensitiveDataLogging();
optionsBuilder.UseNpgsql(Configuration.Shared.GetDatabaseString());
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Person>(builder => {
builder.ToTable("person");
builder.Property(x => x.Id).HasColumnName("nconst");
builder.Property(x => x.FirstName).HasColumnName("firstname");
builder.Property(x => x.LastName).HasColumnName("lastname");
builder.Property(x => x.BirthYear).HasColumnName("birthyear");
builder.HasKey(x => x.Id);
builder.HasMany(x => x.Works).WithOne(x => x.Person).HasForeignKey(x => x.PersonId);
builder.HasOne(x => x.Death).WithOne(x => x.Person).HasForeignKey<Death>(x => x.PersonId);
});
modelBuilder.Entity<Death>(builder => {
builder.ToTable("death");
builder.Property(x => x.PersonId).HasColumnName("nconst");
builder.Property(x => x.DeathYear).HasColumnName("deathyear");
builder.HasKey(x => x.PersonId);
builder.HasOne(x => x.Person).WithOne(x => x.Death).HasForeignKey<Person>(x => x.Id);
});
modelBuilder.Entity<Work>(builder => {
builder.ToTable("_work");
builder.Property(x => x.TitleId).HasColumnName("tconst");
builder.Property(x => x.PersonId).HasColumnName("nconst");
builder.Property(x => x.Job).HasColumnName("job");
builder.HasKey(x => new { x.TitleId, x.PersonId, x.Job });
builder.HasOne(x => x.Title).WithMany(x => x.Staff).HasForeignKey(x => x.TitleId);
builder.HasOne(x => x.Person).WithMany(x => x.Works).HasForeignKey(x => x.PersonId);
});
});
}
}
问题是我可以获取 Person
实例,但它的虚拟属性都是 null
。我知道它与 DataContext
中的外键有关,但我无法弄清楚...我错过了什么?
Person
获取操作
public Person GetPerson(string Id) {
return Context.Persons.Find(Id);
}
失败的测试:
[Fact]
public void Test_GetDeath() {
var person = DataService.GetPerson("nm0113225");
Assert.NotNull(person);
Assert.NotNull(person.Death); // <---- Failure
Assert.Equal("2004", person.Death.DeathYear);
}
PS:我知道一些数据库属性可能会得到改进,但我现在不能。
PS2:这不是我的代码的完整版本,我删除了对我的问题无用的对象。
提前致谢
您必须将 include 添加到您的查询中
Context.Persons. Include(i=>i.Works).FirstOrDefault(i=> i.Id==id );
并且如果您从 Death 中删除 [NotMapped],并添加 Death Id
public int DeathId { get; set; }
public virtual Death Death { get; set; }
并修复你的死亡class,我相信一个人只能有一个死亡
public class Death {
[Key]
public string Id {get; set;}
[StringLength(4, MinimumLength = 4)]
public string DeathYear { get; set; }
public virtual Person Person { get; set; }
}
你可以使用这个查询
Context.Persons.Include(i=>i.Works).Include(i=>i.Death).FirstOrDefault(i=>i.Id==id);
我正在尝试完成这项工作:
namespace DataService.Domain {
public class Death {
[StringLength(10, MinimumLength = 10)]
public string PersonId { get; set; }
[StringLength(4, MinimumLength = 4)]
public string DeathYear { get; set; }
[NotMapped]
public virtual Person Person { get; set; }
}
}
namespace DataService.Domain {
public class Work {
[StringLength(10, MinimumLength = 10)]
public string TitleId { get; set; }
[StringLength(10, MinimumLength = 10)]
public string PersonId { get; set; }
[StringLength(100, MinimumLength = 1)]
public string Job { get; set; }
[NotMapped]
public virtual Title Title { get; set; }
[NotMapped]
public virtual Person Person { get; set; }
}
}
namespace DataService.Domain {
public class Person {
public Person() {
Works = new HashSet<Work>();
}
[StringLength(10, MinimumLength = 10)]
public string Id { get; set; }
[StringLength(100, MinimumLength = 1)]
public string LastName { get; set; }
[StringLength(100, MinimumLength = 1)]
public string FirstName { get; set; }
[StringLength(4, MinimumLength = 4)]
public string BirthYear { get; set; }
[NotMapped]
public virtual ICollection<Work> Works { get; set; }
#nullable enable
[NotMapped]
public virtual Death? Death { get; set; }
#nullable disable
}
}
namespace DataService {
public class DataContext: DbContext {
public DbSet<Person> Persons { get; set; }
public DbSet<Death> Deaths { get; set; }
public DbSet<Work> Works { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
base.OnConfiguring(optionsBuilder);
optionsBuilder.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information);
optionsBuilder.EnableSensitiveDataLogging();
optionsBuilder.UseNpgsql(Configuration.Shared.GetDatabaseString());
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Person>(builder => {
builder.ToTable("person");
builder.Property(x => x.Id).HasColumnName("nconst");
builder.Property(x => x.FirstName).HasColumnName("firstname");
builder.Property(x => x.LastName).HasColumnName("lastname");
builder.Property(x => x.BirthYear).HasColumnName("birthyear");
builder.HasKey(x => x.Id);
builder.HasMany(x => x.Works).WithOne(x => x.Person).HasForeignKey(x => x.PersonId);
builder.HasOne(x => x.Death).WithOne(x => x.Person).HasForeignKey<Death>(x => x.PersonId);
});
modelBuilder.Entity<Death>(builder => {
builder.ToTable("death");
builder.Property(x => x.PersonId).HasColumnName("nconst");
builder.Property(x => x.DeathYear).HasColumnName("deathyear");
builder.HasKey(x => x.PersonId);
builder.HasOne(x => x.Person).WithOne(x => x.Death).HasForeignKey<Person>(x => x.Id);
});
modelBuilder.Entity<Work>(builder => {
builder.ToTable("_work");
builder.Property(x => x.TitleId).HasColumnName("tconst");
builder.Property(x => x.PersonId).HasColumnName("nconst");
builder.Property(x => x.Job).HasColumnName("job");
builder.HasKey(x => new { x.TitleId, x.PersonId, x.Job });
builder.HasOne(x => x.Title).WithMany(x => x.Staff).HasForeignKey(x => x.TitleId);
builder.HasOne(x => x.Person).WithMany(x => x.Works).HasForeignKey(x => x.PersonId);
});
});
}
}
问题是我可以获取 Person
实例,但它的虚拟属性都是 null
。我知道它与 DataContext
中的外键有关,但我无法弄清楚...我错过了什么?
Person
获取操作
public Person GetPerson(string Id) {
return Context.Persons.Find(Id);
}
失败的测试:
[Fact]
public void Test_GetDeath() {
var person = DataService.GetPerson("nm0113225");
Assert.NotNull(person);
Assert.NotNull(person.Death); // <---- Failure
Assert.Equal("2004", person.Death.DeathYear);
}
PS:我知道一些数据库属性可能会得到改进,但我现在不能。
PS2:这不是我的代码的完整版本,我删除了对我的问题无用的对象。
提前致谢
您必须将 include 添加到您的查询中
Context.Persons. Include(i=>i.Works).FirstOrDefault(i=> i.Id==id );
并且如果您从 Death 中删除 [NotMapped],并添加 Death Id
public int DeathId { get; set; }
public virtual Death Death { get; set; }
并修复你的死亡class,我相信一个人只能有一个死亡
public class Death {
[Key]
public string Id {get; set;}
[StringLength(4, MinimumLength = 4)]
public string DeathYear { get; set; }
public virtual Person Person { get; set; }
}
你可以使用这个查询
Context.Persons.Include(i=>i.Works).Include(i=>i.Death).FirstOrDefault(i=>i.Id==id);