首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >实体框架代码优先:如何注释“默认”值的外键?

实体框架代码优先:如何注释“默认”值的外键?
EN

Stack Overflow用户
提问于 2013-03-19 01:24:12
回答 4查看 59K关注 0票数 31

我有两个类:客户端和调查。

每个客户端可以有多个调查,但只能有一个默认调查。

我像这样定义了类:

代码语言:javascript
运行
复制
public class Client
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public string ClientName { get; set; }

    public Nullable<int> DefaultSurveyID { get; set; }

    [ForeignKey("DefaultSurveyID")]
    public virtual Survey DefaultSurvey { get; set; }

    public virtual ICollection<Survey> Surveys { get; set; }
}

public class Survey
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public string SurveyName { get; set; }

    [Required]
    public int ClientID { get; set; }

    [ForeignKey("ClientID")]
    public virtual Client Client { get; set; }
}

正如我所期望的,这将创建客户端表:

代码语言:javascript
运行
复制
[dbo].[Clients]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[ClientName] [nvarchar](max) NULL,
[DefaultSurveyID] [int] NULL
)

但是Survey表有一个额外的外键:

代码语言:javascript
运行
复制
[dbo].[Surveys]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[SurveyName] [nvarchar](max) NULL,
[ClientID] [int] NOT NULL,
[Client_ID] [int] NULL
)

为什么Code First生成这种关系,以及我如何告诉它不生成这种关系?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-03-19 03:22:06

问题是,当你在两个实体之间有多个关系时,EF Code First无法找出哪些导航属性匹配,除非你告诉它如何匹配,以下是代码:

代码语言:javascript
运行
复制
public class Client
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public string ClientName { get; set; }

    /****Change Nullable<int> by int?, looks better****/
    public int? DefaultSurveyID { get; set; }

    /****You need to add this attribute****/
    [InverseProperty("ID")]
    [ForeignKey("DefaultSurveyID")]
    public virtual Survey DefaultSurvey { get; set; }

    public virtual ICollection<Survey> Surveys { get; set; }
}

在以前的版本中,EF创建了额外的关系,因为它不知道DefaultSurvey属性引用了Survey类的ID,但您可以让它知道这一点,添加属性InverseProperty,该属性的参数是Survey中需要DefaultSurvey匹配的属性的名称。

票数 42
EN

Stack Overflow用户

发布于 2013-03-19 02:36:32

你可以使用代码优先,但不是我作弊的代码优先专家:-)

1)我使用SMS在数据库中创建了表和关系(如上所述,没有额外的Client_ID)

2)我使用Reverse Engineer Code First创建了所需的类和映射

3)我删除了数据库并使用context.Database.Create()重新创建了它

原始表定义:

代码语言:javascript
运行
复制
CREATE TABLE [dbo].[Client](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NULL,
    [DefaultSurveyId] [int] NULL,
     CONSTRAINT [PK_dbo.Client] PRIMARY KEY NONCLUSTERED 
    (
        [Id] ASC
    )
)

CREATE TABLE [dbo].[Survey](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NULL,
    [ClientId] [int] NULL,
     CONSTRAINT [PK_dbo.Survey] PRIMARY KEY NONCLUSTERED 
    (
        [Id] ASC
    )
)

加上外键

代码语言:javascript
运行
复制
ALTER TABLE [dbo].[Survey]  WITH CHECK 
    ADD CONSTRAINT [FK_dbo.Survey_dbo.Client_ClientId] FOREIGN KEY([ClientId])
    REFERENCES [dbo].[Client] ([Id])

ALTER TABLE [dbo].[Client]  WITH CHECK 
    ADD CONSTRAINT [FK_dbo.Client_dbo.Survey_DefaultSurveyId] 
    FOREIGN KEY([DefaultSurveyId]) REFERENCES [dbo].[Survey] ([Id])

逆向工程生成的代码:

代码语言:javascript
运行
复制
public partial class Client
{
    public Client()
    {
        this.Surveys = new List<Survey>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public int? DefaultSurveyId { get; set; }
    public virtual Survey DefaultSurvey { get; set; }
    public virtual ICollection<Survey> Surveys { get; set; }
}

public partial class Survey
{
    public Survey()
    {
        this.Clients = new List<Client>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public int? ClientId { get; set; }
    public virtual ICollection<Client> Clients { get; set; }
    public virtual Client Client { get; set; }
}

public class ClientMap : EntityTypeConfiguration<Client>
{
    #region Constructors and Destructors

    public ClientMap()
    {
        // Primary Key
        this.HasKey(t => t.Id);

        // Properties
        this.Property(t => t.Name).HasMaxLength(50);

        // Table & Column Mappings
        this.ToTable("Client");
        this.Property(t => t.Id).HasColumnName("Id");
        this.Property(t => t.Name).HasColumnName("Name");
        this.Property(t => t.DefaultSurveyId).HasColumnName("DefaultSurveyId");

        // Relationships
        this.HasOptional(t => t.DefaultSurvey)
            .WithMany(t => t.Clients).HasForeignKey(d => d.DefaultSurveyId);
    }

    #endregion
}

public class SurveyMap : EntityTypeConfiguration<Survey>
{
    #region Constructors and Destructors

    public SurveyMap()
    {
        // Primary Key
        this.HasKey(t => t.Id);

        // Properties
        this.Property(t => t.Name).HasMaxLength(50);

        // Table & Column Mappings
        this.ToTable("Survey");
        this.Property(t => t.Id).HasColumnName("Id");
        this.Property(t => t.Name).HasColumnName("Name");
        this.Property(t => t.ClientId).HasColumnName("ClientId");

        // Relationships
        this.HasOptional(t => t.Client)
            .WithMany(t => t.Surveys).HasForeignKey(d => d.ClientId);
    }

    #endregion
}
票数 11
EN

Stack Overflow用户

发布于 2013-03-19 01:42:15

Entity Framework完全按照它被告知的那样做。你告诉它的是,客户和调查之间既有一对多的关系,也有一对一的关系。它在Survey表中生成了两个FK,以便映射您请求的两个关系。它不知道你试图将这两种关系联系在一起,我也不认为它有能力处理这一点。

或者,您可能需要考虑在测量对象上添加IsDefaultSurvey字段,以便可以通过客户端对象上的Surveys集合查询默认测量。您甚至可以更进一步,将其作为Client对象的NotMapped属性,以便您仍然可以使用Client.DefaultSurvey来获得正确的调查,而不必更改任何其他代码,如下所示:

代码语言:javascript
运行
复制
[NotMapped]
public Survey DefaultSurvey
{
  get { return this.Surveys.First(s => s.IsDefaultSurvey); }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15483019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档