我试图弄清楚如何使用Entity Framework Core以编程方式生成数据库,并且遇到将外键分配给表中的字段的问题。当我从数据库中检索记录时,我需要地址字段来引用该地址对象并加载它。如果我使用EnsureCreated
创建数据库,则它会正确创建表,除了AddressId字段不是Address表的外键。我尝试对此进行研究,并遇到了this article,它使用了一种称为HasForeignKey
的方法,但是从Entity()返回的任何信息都不知道HasForeignKey
。如果尝试手动输入该错误,则会收到此错误:
错误CS1061'EntityTypeBuilder'不包含定义 用于“ HasForeignKey”,并且不接受扩展方法“ HasForeignKey” 可以找到类型为“ EntityTypeBuilder”的第一个参数 (您是否缺少using指令或程序集引用?)
很明显,这种方法是无效的。我尝试遵循this documentation,但我不太了解它在做什么以及如何将其应用于我的情况。在他们的情况下,他们有几个表,博客和帖子,其中博客有很多帖子,而帖子有一个博客。我尽力做到了,但是我并不太了解所有的术语以及它的作用。
如何简单地将AddressId中的值作为外键分配给Addresses中的记录?这是我正在使用的代码。
public class Person
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public byte Age { get; set; }
public int AddressId { get; set; }
public Address Address { get; set; }
}
public class Address
{
[Key]
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
public class MyContext: DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Address> Addresses { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite($"Data Source=test.db");
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Address>().HasKey(v => v.Id);
builder.Entity<Person>().HasKey(v => v.Id);
}
}
class Program
{
static void Main(string[] args)
{
using (var db = new MyContext())
{
//var person = db.People.Find(1);
db.Database.EnsureCreated();
var person = new Person()
{
FirstName = "Jack",
LastName = "Jackson",
Age = 50,
Address = new Address()
{
Street = "123 Street St",
City = "Jacksonville",
State = "Mississippi",
ZipCode = "00000-0000"
}
};
db.People.Add(person);
db.SaveChanges();
}
}
}
一些额外的信息:
答案 0 :(得分:0)
在您的OnModelCreating方法中,尝试更新以下行以使其看起来像这样(我无法测试此代码,因此我的格式可能已关闭):
builder.Entity<Person>().HasOne(v => v.Address).HasForeignKey(v => v.AddressId);
我相信,由于在两个实体中都具有[Key] Data注释,因此您不需要通过Fluent API设置密钥。警告-我也是EF Core的新手,所以我可能是错的。 :)
答案 1 :(得分:0)
我知道已经晚了,但我希望有人可以从这个答案中受益。我遇到了同样的问题,结果我忘了添加所需的nuget包。安装Microsoft.EntityFrameworkCore.Relational,一切都会好起来。
答案 2 :(得分:0)
尽管这个问题已经过时了,但由于它指出的文档帮助我找出了我自己遇到的另一个问题,我会在此处发布解决方案。
有两种方法可以解决这个问题,一种是使用 ForeignKeyAttribute
注释,另一种是像您使用的那样使用 FluentAPI。可以设置Person有一个或多个地址,对应的方法依此变化。
我还建议在 Address 类中创建一个 Person 属性,这样您也可以反过来使用它们。
第一个是在 Model 类本身中设置的:
public class Person
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// The byte type is interpreted by EF as a boolean or BIT on SQL Server/Sqlite,
// so I took the liberty of changing it to integer
public int Age { get; set; }
public int AddressId { get; set; }
[ForeignKey("AddressId")]
public virtual Address Address { get; set; }
// Set it to be a Collection of any type for a Person to be able to have multiple Addresses
// public ICollection<Address> Addresses { get; set; }
}
public class Address
{
[Key]
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public int PersonId { get; set; }
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
}
另外,如果您想调整约束名称、删除行为或其他额外设置,您可以删除 ForeignKey 属性并使用 Fluent API 来代替:
public class MyContext: DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Address> Addresses { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite($"Data Source=test.db");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>(person =>
{
string tableName = "Persons";
person.ToTable(tableName);
person.HasKey(p => p.Id).HasConstraintName($"PK_{tableName}_Id");
// In case you want to set your Id column to have an Identity/Autoincrement
person.Property(p => p.Id).UseIdentityColumn();
person.Property(p => p.FirstName).HasMaxLength(100);
person.Property(p => p.LastName).HasMaxLength(250);
// Replace HasOne by HasMany in case you want to make a Person
// to be able to have multiple Addresses
person.HasOne(p => p.Address).WithOne(a => a.Person).HasForeignKey("IdAddress").HasConstraintName($"FK_{tableName}_IdAddress").OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<Address>(address => {
string tableName = "Addresses";
address.ToTable(tableName);
address.HasKey(a => a.Id).HasConstraintName($"PK_{tableName}_Id");
// In case you want to set your Id column to have an Identity/Autoincrement
address.Property(a => a.Id).UseIdentityColumn();
address.Property(a => a.Street).HasMaxLength(50);
address.Property(a => a.City).HasMaxLength(30);
address.Property(a => a.State).HasMaxLength(30);
address.Property(a => a.ZipCode).HasMaxLength(10);
// Replace WithOne by WithMany in case you want to make a Person
// to be able to have multiple addresses
address.HasOne(a => a.Person).WithOne(p => p.Address).OnDelete(DeleteBehavior.NoAction);
});
}
}