实体框架:没有主键的表

Cri*_*ris 158 .net entity-framework

我有一个现有的数据库,我想用EF4.0构建一个新的应用程序

某些表没有定义主键,因此当我创建新的实体数据模型时,我收到以下消息:"表/视图TABLE_NAME没有定义主键,也没有推断出有效的主键.此表/视图已被排除.要使用该实体,您需要检查您的架构,添加正确的密钥,并取消注释".

如果我想使用它们并修改数据,我是否必须在这些表中添加PK,或者是否有解决方法以便我不必?

Col*_*lin 106

我认为这是由蒂利托解决的:

实体框架和SQL Server视图

我将在下面引用他的条目:

我们遇到了同样的问题,这就是解决方案:

要强制实体框架使用列作为主键,请使用ISNULL.

要强制实体框架不使用列作为主键,请使用NULLIF.

一种简单的方法是将视图的select语句包装在另一个select中.

例:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp
Run Code Online (Sandbox Code Playgroud)

2010年4月26日17:00由Tillito回答

  • 我不推荐这个.特别是ISNULL部分.如果EF检测到两个PK相同,则可能无法呈现唯一记录,而是返回共享对象.这件事发生在我之前. (8认同)
  • +1这是正确的答案,在完美的世界中,进入并修改所有遗留数据库以具有参照完整性会很棒,但实际上并非总是可行. (6认同)
  • 对于桌子? (3认同)

Dav*_*kle 64

错误意味着它所说的.

即使你可以解决这个问题,相信我,你也不愿意.可引入的令人困惑的错误数量令人震惊和可怕,更不用说你的表现可能会下降.

不要解决这个问题.修复您的数据模型.

编辑:我看到很多人都在贬低这个问题.我想这很好,但请记住,OP询问了如何在没有主键的情况下映射表,而不是视图.答案仍然是一样的.从可管理性,数据完整性和性能的角度来看,解决EF需要在表上使用PK是一个坏主意.

有些人评论说,他们没有能力修复底层数据模型,因为他们正在映射到第三方应用程序.这不是一个好主意,因为模型可以从你身下改变.可以说,在这种情况下,你想要映射到一个视图,这也不是OP所要求的.

  • "修复您的数据模型"并不是一个真正的答案.有时我们必须生活在我们没有创造且不能改变的不太理想的情况下.而且,正如@Colin所说,有一种方法可以完全按照OP的要求进行操作. (138认同)
  • 同意在常见的情况下,但在像LOG表这样的罕见的情况下你只需要尽快插入记录.在检查唯一性和索引发生时,PK可能是一个问题.此外,如果您的PK是IDENTITY,那么将生成的值返回给EF是另一个问题.使用GUID代替?生成时间和索引/排序是另一个问题!...在一些关键的OLTP senarios(如Logging)中没有PK是一个点,并且它没有任何积极的一点! (42认同)
  • 这应该被低估,因为它没有回答这个问题.我们经常需要使用无法更改的第三方数据库. (13认同)
  • 更改代码以满足EF本身就是一种解决方法.并非所有表都需要主键,也不应强制它们.例如,你有一个主题,它有0或很多关键字.关键字表可以具有父主题id和相应的关键字.要说我需要改造我的DB,因为EF强迫我跛脚. (11认同)
  • @MahmoudMoravej:首先,不要混淆群集索引和主键的想法.他们不是一回事.您可以在IDENTITY列上具有聚簇指示的表上具有非常高性能的插入.如果遇到索引维护问题,则应正确分区表.保留没有聚簇索引的表也意味着您无法在删除后有效地对其进行碎片整理以回收空间.如果没有索引,我会怜惜那些试图查询你的日志记录表的人. (4认同)
  • 符合 EF6 与符合 SQL Server(等)不同。答案仍然有效,但在不排除所有其他因素的情况下,您不能诚实地同意这是正确的决定。我希望答案是“这就是你如何做”,而不是“不要这样做”。但事实并非如此。 (3认同)
  • 您可以拥有非群集PK,在某些情况下我经常这样做.例如,在日志记录情况下,我的PK可能是IDENTITY,但我的聚集索引通常在时间上,因为按时间聚类会加快范围扫描.按时间对这些表进行分区通常也是个好主意.通过这种方式,您可以选择仅对最新分区执行索引维护和扫描(根据需要).就插入性能而言,你是正确的,因为使用未编制索引的表可以更快地插入,但查询速度要慢得多. (2认同)
  • @Tim:不确定“不是解决方案”是什么意思。拥有一个没有至少一个候选键的生产、非暂存、永久表*始终是一个问题*,因此根据定义选择合适的候选键*始终是一种解决方案*。对于那里的反对者,请随意反对这一点,但OP询问的是*表*,而不是视图。对于这个具体问题,这个答案仍然是最好的建议。 (2认同)

Cod*_*und 20

如果我想使用它们并修改数据,我是否必须在这些表中添加PK,或者是否有解决方法以便我不必?

对于那些达到这个问题并且正在使用Entity Framework Core的人来说,您不再需要为表格添加PK或进行任何解决方法.自EF Core 2.1以来,我们有一个新功能查询类型

查询类型必须用于:

  • 用作ad hoc FromSql()查询的返回类型.
  • 映射到数据库视图.
  • 映射到未定义主键的表.
  • 映射到模型中定义的查询.

所以在你的DbContext中只需添加以下类型的属性,DbQuery<T>而不是DbSet<T>像下面那样.假设您的表名是MyTable:

public DbQuery<MyTable> MyTables { get; set; }
Run Code Online (Sandbox Code Playgroud)


Adr*_*cia 16

复合键也可以使用Entity Framework Fluent API完成

public class MyModelConfiguration : EntityTypeConfiguration<MyModel>
{
     public MyModelConfiguration()
     {
        ToTable("MY_MODEL_TABLE");
        HasKey(x => new { x.SourceId, x.StartDate, x.EndDate, x.GmsDate });
        ...
     }
}
Run Code Online (Sandbox Code Playgroud)


viv*_*una 9

在 EF Core 5.0 中,您还可以在实体级别定义它。

[Keyless]
public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public int Zip { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

参考: https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew#use-ac-attribute-to-indicate-that-an-entity-无钥匙


Bar*_*rny 5

这个解决方案有效

即使您没有PK,也不需要手动映射.您只需要告诉EF您的某个列是索引,索引列不可为空.

为此,您可以使用isNull函数向视图添加行号,如下所示

select 
    ISNULL(ROW_NUMBER() OVER (ORDER BY xxx), - 9999) AS id
from a
Run Code Online (Sandbox Code Playgroud)

ISNULL(id, number) 这是关键点,因为它告诉EF这个列可以是主键

  • 我不建议ISNULL部分.如果EF检测到两个PK相同,则可能无法呈现唯一记录,而是返回共享对象.这件事发生在我之前. (2认同)

Bor*_*itz 5

在我的情况下,我必须将实体映射到View,它没有主键.而且,我不允许修改此视图.幸运的是,这个View有一个唯一的字符串列.我的解决方案是将此列标记为主键:

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[StringLength(255)]
public string UserSID { get; set; }
Run Code Online (Sandbox Code Playgroud)

被骗的EF.工作得很完美,没有人注意到...... :)


归档时间:

查看次数:

151592 次

最近记录:

7 年,5 月 前