2017-04-12 109 views
0

我有以下型号:增加0..1关系在EF代码首先

public class ItemRental 
{ 
    [Key] 
    public Int32 ItemRentalId { get; set; } 

    public Int32 ItemId { get; set; } 
    public Int32 ChargeItemId { get; set; } 

    [ForeignKey("ItemId")] 
    public Item Item { get; set; } 

    [ForeignKey("ChargeItemId")] 
    public Item ChargeItem { get; set; } 
} 

public class Item 
{ 
    [Key] 
    public Int32 ItemId { get; set; } 

    public Int32? ItemRentalId { get; set; } 

    [ForeignKey("ItemRentalId")] 
    public ItemRental ItemRental { get; set; } 
} 

ItemRentalItem一个1..1关系,并与ChargeItem一个1..N关系。

问题是我需要一个关系,从Item回到ChargeItem,所以在Item上添加属性ItemRentalId。这是可空的,因为不是每个Item必须有ItemRental

是否有可能创建这种关系只是注释?

我尝试了一口流利的API:

 modelBuilder.Entity<Item>() 
        .HasOptional(m => m.ItemRental) 
        .WithRequired(c => c.ChargeItem) 
        .Map(p => p.MapKey("ItemRentalId")); 

但这样做迁移后是不使用ChargeItemId的关系。

问题是,当我运行这个迁移它不承认作为FK导航属性ItemRentalId

回答

1

所以,如果我理解正确,你的问题是与一个映射到零或一个关系。 您遇到的是实体框架的一个设计特性。处理一对一关系(及其可选对象)很棘手,原因很多。当你这样做时,你不能在你的模型—中指定外键,而是你的实体的主键也是主体端的外键,不能指定额外的FK。

有关详细信息,请参阅下面的内容。


映射一到零或一个

所以我们可以说,你有以下型号:

public class Person 
{ 
    public int PersonId { get; set; } 
    public string Name { get; set; } 
} 

public class Car 
{ 
    public int CarId { get; set; } 
    public string LicensePlate { get; set; } 
} 

public class MyDemoContext : DbContext 
{ 
    public DbSet<Person> People { get; set; } 
    public DbSet<Car> Cars { get; set; } 
} 

现在你想设定,让你可以表示以下规范:一个人可以有一辆或零辆车,并且每辆车都完全属于一个人(关系是双向的,所以如果CarA属于PersonA,那么PersonA'拥有'CarA)。

,让我们修改模型中的位:添加导航属性和外键的属性:

public class Person 
{ 
    public int PersonId { get; set; } 
    public string Name { get; set; } 
    public int CarId { get; set; } 
    public virtual Car Car { get; set; } 
} 

public class Car 
{ 
    public int CarId { get; set; } 
    public string LicensePlate { get; set; } 
    public int PersonId { get; set; } 
    public virtual Person Person { get; set; } 
} 

而且配置:

public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car> 
{ 
    public CarEntityTypeConfiguration() 
    { 
    this.HasRequired(c => c.Person).WithOptional(p => p.Car);       
    } 
}  

这个时候,这应该是不言自明的。该车有一个需要的人(HasRequired()),该人有一辆可选车(WithOptional())。同样,你配置这种关系的哪一方并不重要,只要在使用Has/With和Required/Optional的正确组合时小心。从Person方面,它应该是这样的:

public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person> 
{ 
    public PersonEntityTypeConfiguration() 
    { 
    this.HasOptional(p => p.Car).WithOptional(c => c.Person);       
    } 
}  

现在让我们来看看DB模式:

仔细查看:你可以看到,有没有FK在People指到Car。另外,Car中的FK不是PersonId,而是CarId。下面是为FK的实际脚本:

ALTER TABLE [dbo].[Cars] WITH CHECK ADD CONSTRAINT [FK_dbo.Cars_dbo.People_CarId] FOREIGN KEY([CarId]) 
REFERENCES [dbo].[People] ([PersonId]) 

因此,这意味着我们有CarIdPersonId foregn关键属性模型基本上忽略。它们在数据库中,但它们不是外键,因为它可能是预期的。这是因为一对一映射不支持将FK添加到EF模型中。这是因为一对一映射在关系数据库中是相当成问题的。

这个想法是每个人都可以有一辆车,而那辆车只能属于那个人。或者可能有人员记录,没有与他们相关的汽车。

那么这怎么可能用外键表示呢?显然,Car中可能有PersonIdPeople中有CarId。为了强制每个人只能有一辆车,PersonId必须是唯一的Car。但是,如果PersonIdPeople中是唯一的,那么如何添加两个或多个记录,其中PersonIdNULL(多辆车没有车主)?答:你不能(事实上,你可以在SQL Server 2008和更新的版本中创建一个过滤的唯一索引,但让我们暂时忘记这个技术性问题;更别说其他RDBMS了)。更不用说您指定关系的两端的情况...

如果PeopleCar表具有“相同”主键(连接记录中的值相同),则唯一可行的方法是执行此规则, 。要做到这一点,CarIdCar必须是一个PK和一个FK的人民PK。这使得整个模式变得混乱。当我使用这个我宁愿命名PK/FK在CarPersonId,并相应地对其进行配置:

public class Person 
{ 
    public int PersonId { get; set; } 
    public string Name { get; set; }   
    public virtual Car Car { get; set; } 
} 

public class Car 
{   
    public string LicensePlate { get; set; } 
    public int PersonId { get; set; } 
    public virtual Person Person { get; set; } 
} 

public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car> 
{ 
    public CarEntityTypeConfiguration() 
    { 
    this.HasRequired(c => c.Person).WithOptional(p => p.Car); 
    this.HasKey(c => c.PersonId); 
    } 
} 

并不理想,但也许会好一点。但是,使用此解决方案时必须保持警惕,因为它违背了通常的命名约定,可能会导致您误入歧途。下面是从这个模型生成的架构:

所以这种关系不是由数据库架构强制执行,但通过实体框架本身。这就是为什么当你使用这个时你必须非常小心,而不是让任何人直接用数据库来锻炼。

+0

那么这是EF或Sql服务器的设计限制吗?必须有办法可以定义导航属性的FK名称权限? – YesMan85

+0

我想这是两个。在关系型数据库中有一个真正的1-1是不可能的,所以你必须在EF中做一些技巧。另外,如果向FK添加一个唯一约束,则只有一个1-1关联才是可行的。我想这就是EF进入并解决这些问题的原因,因为它引入了这个限制。 –

+0

是的,我多玩了一会儿,我能够在SQL服务器中以黑客的方式创建关系,但无法让它在EF中工作。现在决定改变数据模型。 – YesMan85