【问题标题】:How can I properly retrieve the virtual properties of my Data object with foreign keys? [duplicate]如何使用外键正确检索 Data 对象的虚拟属性? [复制]
【发布时间】:2021-11-11 14:20:44
【问题描述】:

我正在努力做到这一点:

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:我知道某些 DB 属性可能会得到改进,但我现在还不能。

PS2:这不是我的代码的完整版本,我已经删除了对我的问题无用的对象。

提前谢谢你

【问题讨论】:

  • 您必须显示您用于获取的操作
  • @Serge 抱歉,已更新。这是一个简单的 Context.Persons.Find(Id)
  • 你听说过Include吗?
  • @SvyatoslavDanyliv 确实是的,但在我几天前尝试的时候它不起作用......谢谢!

标签: c# entity-framework entity-framework-core


【解决方案1】:

您必须在查询中添加包含

  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; }

并修复你的死亡等级,我相信一个人只能有一个死亡

 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);

【讨论】:

  • 当我将Include 添加到操作时,Person 为空
  • @AlexisChoupault 抱歉打错了,试试 i.Id==id
  • 不,是我:当我将双向外键删除为单向外键时,它似乎起作用了。谢谢!
  • @AlexisChoupault 欢迎您!不要忘记接受答案。用户应该知道什么是有效的。否则它将被否决。
猜你喜欢
  • 2017-04-22
  • 2010-10-15
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 2019-05-30
  • 2013-11-16
相关资源
最近更新 更多