将导航属性映射到实例var为外键 [英] Map a navigation property to a instance var as Foreign key
问题描述
我正在使用.Net Framework 4.0开发实体框架代码(v.4.4.0.0)C#库。
我不知道如何设置零对一的关系。我的模型如下:
一个 Talk
只能由一个用户创建( StarterUserId
)。
A Talk
只能有一个收件人用户( RecepientUserId
)或只有一个组( RecipientGroupId
)。如果 RecipientGroupId
RecepientUserId 为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));
如果你这样做,你必须删除来自
属性,否则EF会抱怨两个具有相同名称的冲突列。 Talk
类的RecipientGroupId
我相信,可选:可选是独立关系的唯一一对一关系,所有其他关系都是外键关键字,其中外键属性是主键属性的同时(根据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 RecipientGroupId
is not null; or RecepientUserId
is not null if RecipientGroupId
is 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为外键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!