我有两个类:客户端和调查。
每个客户端可以有多个调查,但只能有一个默认调查。
我像这样定义了类:
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; }
}
正如我所期望的,这将创建客户端表:
[dbo].[Clients]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[ClientName] [nvarchar](max) NULL,
[DefaultSurveyID] [int] NULL
)
但是Survey表有一个额外的外键:
[dbo].[Surveys]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[SurveyName] [nvarchar](max) NULL,
[ClientID] [int] NOT NULL,
[Client_ID] [int] NULL
)
为什么Code First生成这种关系,以及我如何告诉它不生成这种关系?
发布于 2013-03-19 03:22:06
问题是,当你在两个实体之间有多个关系时,EF Code First无法找出哪些导航属性匹配,除非你告诉它如何匹配,以下是代码:
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
匹配的属性的名称。
发布于 2013-03-19 02:36:32
你可以使用代码优先,但不是我作弊的代码优先专家:-)
1)我使用SMS在数据库中创建了表和关系(如上所述,没有额外的Client_ID)
2)我使用Reverse Engineer Code First创建了所需的类和映射
3)我删除了数据库并使用context.Database.Create()重新创建了它
原始表定义:
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
)
)
加上外键
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])
逆向工程生成的代码:
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
}
发布于 2013-03-19 01:42:15
Entity Framework完全按照它被告知的那样做。你告诉它的是,客户和调查之间既有一对多的关系,也有一对一的关系。它在Survey表中生成了两个FK,以便映射您请求的两个关系。它不知道你试图将这两种关系联系在一起,我也不认为它有能力处理这一点。
或者,您可能需要考虑在测量对象上添加IsDefaultSurvey
字段,以便可以通过客户端对象上的Surveys
集合查询默认测量。您甚至可以更进一步,将其作为Client对象的NotMapped
属性,以便您仍然可以使用Client.DefaultSurvey
来获得正确的调查,而不必更改任何其他代码,如下所示:
[NotMapped]
public Survey DefaultSurvey
{
get { return this.Surveys.First(s => s.IsDefaultSurvey); }
}
https://stackoverflow.com/questions/15483019
复制相似问题