基本上我有一个像:
这样的实体public class Person {
public int PersonId { get; set; }
public string Name { get; set; }
public Address Hometown { get; set; }
}
和类似:
public class Address {
public City City { get; set; }
public string Province { get; set; }
}
我想要完成的是将垂直连接两个类并拥有一个带行的表:
TB_PERSON:
PersonId PK
Name
City_id FK
Province
为什么我想要这种方法,在我的实际项目中,我在多个条目上发生了相同类型的数据结构模式,在这种情况下,示例将是地址类。它可能很容易出现在另一个实体中。
难道我几天都找不到怎么办?我能得到的是最复杂的类型,但在这种情况下它们不允许导航属性。我希望访问并使我的行数据类型化,面向对象,以为EF会有所作为。任何帮助表示赞赏。
答案 0 :(得分:3)
ComplexType应该是一个解决方案但不幸的是:
复杂类型不能包含导航属性。 Source
变通方法列表:
使用表格拆分的解决方法
public class Person
{
public int PersonID { get; set; }
public string Name { get; set; }
public virtual Address Address { get; set; }
}
public class Address
{
public Int32 ID { get; set; }
public string Province { get; set; }
public virtual City City { get; set; }
}
public class City
{
public Int32 CityID { get; set; }
public string Name { get; set; }
}
public class MappingContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Address> Addresses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Address>()
.HasKey(t => t.ID)
.HasOptional(t => t.City)
.WithMany()
.Map(t => t.MapKey("CityID"));
modelBuilder.Entity<Address>()
.Property(t => t.ID)
.HasColumnName("PersonID");
modelBuilder.Entity<Person>()
.HasKey(t => t.PersonID)
.HasRequired(t => t.Address)
.WithRequiredPrincipal();
modelBuilder.Entity<Person>().ToTable("TB_PERSON");
modelBuilder.Entity<Address>().ToTable("TB_PERSON");
modelBuilder.Entity<City>()
.HasKey(t => t.CityID)
.ToTable("City");
}
}
[使用方法]
using (var db = new MappingContext())
{
var person = db.Persons.FirstOrDefault();
var cityName = person.Address.City.Name;
var address = db.Addresses.FirstOrDefault();
var personName = address.Person.Name;
}
[数据库]
CREATE TABLE [dbo].[City](
[CityID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[TB_PERSON](
[PersonId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
[Province] [varchar](50) NULL,
[CityID] [int] NULL
) ON [PRIMARY]
使用表拆分+ TPC继承的解决方法(对于可重用的地址类)
TB_CUSTOMER是另一个包含地址列的表。
public class Person
{
public int PersonID { get; set; }
public string Name { get; set; }
public virtual PersonAddress Address { get; set; }
}
public class Address
{
public string Province { get; set; }
public virtual City City { get; set; }
}
public class PersonAddress : Address
{
public Int32 PersonID { get; set; }
public virtual Person Person { get; set; }
}
public class CustomerAddress : Address
{
public Int32 CustomerID { get; set; }
}
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
public virtual CustomerAddress Address { get; set; }
}
public class City
{
public Int32 CityID { get; set; }
public string Name { get; set; }
}
public class MappingContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<PersonAddress> PersonAddresses { get; set; }
public DbSet<CustomerAddress> CustomerAddresses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<PersonAddress>()
.HasKey(t => t.PersonID)
.HasOptional(t => t.City)
.WithMany()
.Map(t => t.MapKey("CityID"));
modelBuilder.Entity<CustomerAddress>()
.HasKey(t => t.CustomerID)
.HasOptional(t => t.City)
.WithMany()
.Map(t => t.MapKey("CityID"));
modelBuilder.Entity<Person>()
.HasRequired(t => t.Address)
.WithRequiredPrincipal(t => t.Person);
modelBuilder.Entity<Customer>()
.HasRequired(t => t.Address)
.WithRequiredPrincipal();
modelBuilder.Entity<Person>().ToTable("TB_PERSON");
modelBuilder.Entity<PersonAddress>().ToTable("TB_PERSON");
modelBuilder.Entity<Customer>().ToTable("TB_CUSTOMER");
modelBuilder.Entity<CustomerAddress>().ToTable("TB_CUSTOMER");
modelBuilder.Entity<City>()
.HasKey(t => t.CityID)
.ToTable("City");
}
}
使用IAddress进行解决方法
public class Person : IAddress
{
public int PersonID { get; set; }
public string Name { get; set; }
public string Province { get; set; }
public virtual City City { get; set; }
[NotMapped]
public IAddress Address { get { return this; } }
}
public interface IAddress
{
string Province { get; set; }
City City { get; set; }
}
public class City
{
public Int32 CityID { get; set; }
public string Name { get; set; }
}
public class MappingContext : DbContext
{
public DbSet<Person> Persons { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasKey(t => t.PersonID)
.HasOptional(t => t.City)
.WithMany()
.Map(t => t.MapKey("CityID"));
modelBuilder.Entity<Person>().ToTable("TB_PERSON");
modelBuilder.Entity<City>()
.HasKey(t => t.CityID)
.ToTable("City");
}
}
答案 1 :(得分:1)
除了Table分割之外,还有2种解决方法(不是解决方案)。
继承
创建Address类并在每个应该有地址的类中继承它 地址属性与其他属性混合在一起(实际上我认为在您的情况下我不会应用此解决方案)。
1-1关系
(如果更多实体可以共享相同的地址,则为n-1关系)
型号:
public class ClassA
{
public int Id { get; set; }
public string Description { get; set; }
public virtual ClassB ClassB { get; set; }
}
public class ClassB
{
public int Id { get; set; }
public string Description { get; set; }
public virtual ClassA ClassA { get; set; }
}
背景信息:
class Context : DbContext
{
public Context(DbConnection connection)
: base(connection, false)
{ }
public DbSet<ClassA> As { get; set; }
public DbSet<ClassB> Bs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ClassB>().HasOptional(c => c.ClassA).WithOptionalDependent(c => c.ClassB);
}
}
DDL声明:
ExecuteNonQuery==========
CREATE TABLE [ClassAs] (
[Id] int not null identity(1,1)
, [Description] text null
);
ALTER TABLE [ClassAs] ADD CONSTRAINT [PK_ClassAs_9cd06620] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE TABLE [ClassBs] (
[Id] int not null identity(1,1)
, [Description] text null
, [ClassA_Id] int null
);
ALTER TABLE [ClassBs] ADD CONSTRAINT [PK_ClassBs_9cd06620] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE INDEX [IX_ClassA_Id] ON [ClassBs] ([ClassA_Id])
ExecuteNonQuery==========
ALTER TABLE [ClassBs] ADD CONSTRAINT [FK_ClassBs_ClassAs_ClassA_Id] FOREIGN KEY ([ClassA_Id]) REFERENCES [ClassAs] ([Id])
在第二种情况下,您可以删除ClassB.ClassA导航属性,以便跨多种类型共享ClassB。这里的问题是你有2个表
答案 2 :(得分:0)
几乎所有复杂的导航都可以使用流畅的api。
Google这些:Fluent Api和EntityTypeConfiguration