将导航属性映射到实例var作为外键

时间:2013-11-27 10:56:45

标签: c# sql entity-framework database-design entity-relationship

我正在使用.Net Framework 4.0开发一个实体框架代码优先(v.4.4.0.0)C#库。

我不知道如何设置零对一关系。我的模型如下:

Talk只能由一位用户(StarterUserId)创建 Talk只能有一个收件人用户(RecepientUserId)或只有一个用户组RecipientGroupId)。
注意:这意味着如果RecepientUserId不为空,则RecipientGroupId为空;如果RecepientUserId为空,则RecipientGroupId不为空。

user可以是零或n Talks的收件人,但group可以是零或一Talk

这是 Talk 类:

[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; }
}

使用 TalkConfiguration 类:

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);
    }
}

这是Group类:

[DataContract]
public class Group
{
    [DataMember]
    public int GroupId { get; set; }

    [ ... ]

    public Talk GroupTalk { get; set; }
}

GroupConfiguration类:

class GroupConfiguration : EntityTypeConfiguration<Group>
{
    public GroupConfiguration()
    {
        [ ... ] // Nothing related to GroupTalk
    }
}

通过这些类和配置,我在数据库中获得了这个Talk表:

enter image description here

我想将Talk.RecipientGroupId作为 FOREIGN KEY 设为Group.GroupId。但是,此模型会创建另一列Talk.RecipientGroup_GroupId作为 FOREIGN KEY Group.GroupId。而且,我不希望这样。

我该怎么做?

1 个答案:

答案 0 :(得分:1)

可选:可选的一对一关系映射为独立关联,而不是外键关联,这意味着您不能在模型类中拥有外键属性。这就是为什么你不能在HasForeignKey之后链接WithOptionalDependent。而且我非常确定[ForeignKey]上的RecipientGroupId属性被忽略了,EF认为RecipientGroupId是一个普通的标量属性而没有任何关系。

在数据库模式本身中,该关系具有外键。这是您使用自动生成的默认名称看到的那个:RecipientGroup_GroupId。但是不支持将此外键映射到属性。但是,我认为您可以使用MapKey

重命名该列
HasOptional(t => t.RecipientGroup)
    .WithOptionalDependent(g => g.GroupTalk)
    .Map(m => m.MapKey("RecipientGroupId"));

如果你这样做,你必须RecipientGroupId类删除Talk属性,否则EF会抱怨两个具有相同名称的冲突列。

我相信,可选:可选是唯一的一对一关系,它们是独立关联,所有其他关键是外键关联,其中外键属性同时是主键属性(根据Arthur Vickers的回答)在this thread的底部。使用可选:可选关系,这是不可能的,因为主键属性不能为空。

由于您的RecipientGroupId具有[DataMember]属性,因此您希望在某些服务边界上传输该值,因此出于某种原因需要外键作为属性值。在这种情况下,我选择的解决方法是将Talk<->Group关系映射为一对多关系,而Group类中没有任何导航属性(将其映射到无参数{{1}调用then)或使用集合导航属性,然后在业务逻辑中确保此集合不能包含多个元素。