问题描述
我正在使用.Net Framework 4.0开发实体框架代码(v.4.4.0.0)C#库。
我不知道如何设置零对一的关系。我的模型如下:
一个 Talk 只能由一个用户创建( StarterUserId )。
A Talk 只能有一个收件人用户( RecepientUserId )或只有一个组( RecipientGroupId )。如果 RecipientGroupId 为null >不为空;或 RecepientUserId 不为空,如果 RecipientGroupId 为null。
用户可以是零或n Talks 的收件人,但是组可以有零个或一个 Talk 。
这是 Talk 类:
[DataContract]
public class Talk
{
[DataMember]
public int TalkId {get;组; }
[DataMember]
public int StarterUserId {get;组;
[DataMember]
public int? RecipientUserId {get;组;
[DataMember]
[ForeignKey(RecipientGroup)]
public int? RecipientGroupId {get;组; }
public DateTime DateUtcStarted {get;组; }
[DataMember]
public string DateStarted
{
get
{
return DateUtcStarted.ToString(dd / MM / yyyy HH :mm);
}
set
{
DateUtcStarted = DateTime.Parse(value);
}
}
public用户StarterUser {get;组; }
public User RecipientUser {get;组; }
public Group RecipientGroup {get;组; }
}
使用这个 TalkConfiguration 类:
class TalkConfiguration:EntityTypeConfiguration< Talk>
{
public TalkConfiguration()
{
属性(t => t.StarterUserId).IsRequired();
属性(t => t.RecipientUserId).IsOptional();
属性(t => t.RecipientGroupId).IsOptional();
Property(t => t.DateUtcStarted).IsRequired();
忽略(t => t.DateStarted);
HasRequired(t => t.StarterUser)。
WithMany(u => u.TalksStarted)。
HasForeignKey(t => t.StarterUserId);
HasOptional(t => t.RecipientUser)。
WithMany(u => u.InTalks)。
HasForeignKey(t => t.RecipientUserId);
HasOptional(t => t.RecipientGroup).WithOptionalDependent(g => g.GroupTalk);
}
}
这是 class:
[DataContract]
public class Group
{
[DataMember]
public int GroupId {get;组; }
[...]
public Talk GroupTalk {get;组; }
}
而$ code> GroupConfiguration class:
class GroupConfiguration:EntityTypeConfiguration< Group>
{
public GroupConfiguration()
{
[...] //与GroupTalk无关的
}
}
使用这些类和配置,我在数据库中获取这个 Talk 表: p>
我想使 Talk.RecipientGroupId 作为 FOREIGN KEY 到 Group.GroupId 。但是,此模型会将 Talk.RecipientGroup_GroupId 另一列作为 FOREIGN KEY 创建为 Group.GroupId 。
我该怎么做?
可选:可选的一对一关系映射为独立关系,而不是外键关联,这意味着您的模型类中不能有外键属性。这就是为什么你不能在 WithOptionalDependent 之后连接 HasForeignKey 。而且我很确定 RecipientGroupId 上的 [ForeignKey] 属性被忽略,EF认为 RecipientGroupId 作为没有关系目的的普通标量属性。
在数据库模式本身中,关系有一个外键。这是您使用自动生成的默认名称查看的内容: RecipientGroup_GroupId 。但不支持将此外键映射到属性。但是,我想您可以使用 MapKey
HasOptional( t => t.RecipientGroup)
.WithOptionalDependent(g => g.GroupTalk)
.Map(m => m.MapKey(RecipientGroupId));
如果你这样做,你必须删除来自 Talk 类的RecipientGroupId 属性,否则EF会抱怨两个具有相同名称的冲突列。
我相信,可选:可选是独立关系的唯一一对一关系,所有其他关系都是外键关键字,其中外键属性是主键属性的同时(根据Arthur Vickers '回答在)。使用可选关系,这是不可能的,因为主键属性不能为空。
由于您的 RecipientGroupId 具有一个 [DataMember] 属性,它看起来要传输一些服务边界的值,因此由于某些原因需要外键作为属性值。在这种情况下,我将选择的解决方法是将 Talk< - > Group 关系映射为一对多关系,其中没有导航属性在组类(使用无参数 WithMany()调用),或使用集合导航属性,然后确保业务逻辑该集合不能包含多个元素。
I'm developing an Entity Framework Code First (v. 4.4.0.0) C# library with .Net Framework 4.0.
I don't know how to set zero-to-one relationship. My model is the following:
A Talk can be created by only one user (StarterUserId).
A Talk can have only one recipient user (RecepientUserId) or only one group (RecipientGroupId).
Note: That means that RecepientUserId is null if RecipientGroupIdis not null; or RecepientUserId is not null if RecipientGroupIdis null.
A user can be a recipient of zero or n Talks, but a group can have zero or one Talk.
This is Talk class:
[DataContract] public class Talk { [DataMember] public int TalkId { get; set; } [DataMember] public int StarterUserId { get; set; } [DataMember] public int? RecipientUserId { get; set; } [DataMember] [ForeignKey("RecipientGroup")] public int? RecipientGroupId { get; set; } public DateTime DateUtcStarted { get; set; } [DataMember] public string DateStarted { get { return DateUtcStarted.ToString("dd/MM/yyyy HH:mm"); } set { DateUtcStarted = DateTime.Parse(value); } } public User StarterUser { get; set; } public User RecipientUser { get; set; } public Group RecipientGroup { get; set; } }
With this TalkConfiguration class:
class TalkConfiguration : EntityTypeConfiguration<Talk> { public TalkConfiguration() { Property(t => t.StarterUserId).IsRequired(); Property(t => t.RecipientUserId).IsOptional(); Property(t => t.RecipientGroupId).IsOptional(); Property(t => t.DateUtcStarted).IsRequired(); Ignore(t => t.DateStarted); HasRequired(t => t.StarterUser). WithMany(u => u.TalksStarted). HasForeignKey(t => t.StarterUserId); HasOptional(t => t.RecipientUser). WithMany(u => u.InTalks). HasForeignKey(t => t.RecipientUserId); HasOptional(t => t.RecipientGroup).WithOptionalDependent(g => g.GroupTalk); } }
And this is the Group class:
[DataContract] public class Group { [DataMember] public int GroupId { get; set; } [ ... ] public Talk GroupTalk { get; set; } }
And the GroupConfiguration class:
class GroupConfiguration : EntityTypeConfiguration<Group> { public GroupConfiguration() { [ ... ] // Nothing related to GroupTalk } }
With these classes and configurations I get this Talk table at database:
I want to make Talk.RecipientGroupId as a FOREIGN KEY to Group.GroupId. But this model creates another column, Talk.RecipientGroup_GroupId as FOREIGN KEY to Group.GroupId. And, I don't want that.
How can I do it?
Optional:optional one-to-one relationships are mapped as independent associations, not as foreign key associations which means that you can't have a foreign key property in your model class. That's why you can't chain HasForeignKey after WithOptionalDependent. And I'm pretty sure that the [ForeignKey] attribute on RecipientGroupId is simply ignored and EF considers RecipientGroupId as an ordinary scalar property with no relationship purpose.
In the database schema itself the relationship has a foreign key. That's the one you are seeing with an autogenerated default name: RecipientGroup_GroupId. But it's not supported to map this foreign key to a property. However, I think you can rename the column using MapKey
HasOptional(t => t.RecipientGroup) .WithOptionalDependent(g => g.GroupTalk) .Map(m => m.MapKey("RecipientGroupId"));
If you do that you must remove the RecipientGroupId property from the Talk class, otherwise EF will complain about two conflicting columns with the same name.
I believe, optional:optional are the only one-to-one relationships that are independent associations, all other are foreign key associations where the foreign key property is the primary key property at the same time (according to Arthur Vickers' answer at the bottom of this thread). With optional:optional relationships this would be impossible because a primary key property cannot be nullable.
Since your RecipientGroupId has a [DataMember] attribute it looks that you want to transmit the value over some service boundary and therefore need the foreign key as property value for some reason. In this case the workaround that I would choose is mapping the Talk<->Group relationship as one-to-many relationship with either no navigation property in the Group class at all (mapping it with a parameterless WithMany() call then) or with a collection navigation property and ensure then in business logic that this collection cannot contain more than one element.
这篇关于将导航属性映射到实例var为外键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!