实体框架:没有主键的表

时间:2010-10-22 12:32:44

标签: .net entity-framework

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

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

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

19 个答案:

答案 0 :(得分:103)

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

Entity Framework and SQL Server View

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

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

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

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

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

示例:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp

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

答案 1 :(得分:61)

错误意味着它所说的内容。

即使你可以解决这个问题,相信我,你也不愿意。可引入的混乱错误的数量是惊人的,可怕的,更不用说你的表现可能会下降。

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

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

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

答案 2 :(得分:15)

复合键也可以使用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 });
        ...
     }
}

答案 3 :(得分:10)

  

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

对于那些达到此问题且正在使用Entity Framework Core的人,您不再需要为表格添加PK或执行任何变通方法。自EF Core 2.1起,我们有了一项新功能Query Types

查询类型必须用于:

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

因此,在您的DbContext中,只需添加以下DbQuery<T>类型的属性,而不是DbSet<T>,如下所示。假设您的表名为MyTable

public DbQuery<MyTable> MyTables { get; set; }

答案 4 :(得分:6)

此解决方案工作

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

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

select 
    ISNULL(ROW_NUMBER() OVER (ORDER BY xxx), - 9999) AS id
from a

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

答案 5 :(得分:5)

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

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[StringLength(255)]
public string UserSID { get; set; }

欺骗EF。工作得很好,没有人注意到...... :)。

答案 6 :(得分:4)

EF不需要数据库上的主键。如果是,则无法将实体绑定到视图。

您可以修改SSDL(和CSDL)以指定唯一字段作为主键。如果你没有一个独特的领域,那么我相信你已经被软化了。但是你真的应该有一个独特的领域(和PK),否则你以后会遇到问题。

埃里克

答案 7 :(得分:2)

如果你真的没有PK,上述答案是正确的。

但是如果有一个,但是没有在DB中指定索引,并且你无法更改数据库(是的,我在Dilbert的世界中工作),你可以手动将字段映射为键。

答案 8 :(得分:2)

拥有无用的身份密钥有时毫无意义。我发现如果没有使用ID,为什么要添加它?但是,实体对此并不那么宽容,因此添加ID字段将是最好的。即使在没有使用它的情况下,它也比处理Entity关于丢失的身份密钥的不完整错误更好。

答案 9 :(得分:2)

这只是@Erick T的答案的补充。如果没有包含唯一值的单个列,则解决方法是使用复合键,如下所示:

[Key]
[Column("LAST_NAME", Order = 1)]
public string LastName { get; set; }

[Key]
[Column("FIRST_NAME", Order = 2)]
public string FirstName { get; set; }

同样,这只是一种解决方法。真正的解决方案是修复数据模型。

答案 10 :(得分:1)

  1. 更改表格结构并添加主列。更新模型
  2. 在XML编辑器中修改.EDMX文件并尝试在此特定表的标记下添加新列(不会工作)
  3. 我会,而不是创建一个新的主列到退出表 通过涉及所有现有列(工作
  4. 来制作复合键

    Entity Framework: Adding DataTable with no Primary Key to Entity Model.

答案 11 :(得分:1)

更新为@CodeNotFound的答案。

在EF Core 3.0中,DbQuery<T>已过时,您应该使用Keyless entity types来实现相同的目的。这些是使用ModelBuilder HasNoKey()方法配置的。在您的DbContext类中,执行此操作

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<YourEntityType>(eb =>
        {
            eb.HasNoKey();
        });

}

但是有一些限制,特别是:

  • 从不跟踪DbContext中的更改,因此从不插入,更新或删除数据库。
  • 仅支持导航映射功能的子集,尤其是:
    • 他们可能永远不会成为恋爱关系的主要目的。
    • 他们可能没有到拥有实体的导航
    • 它们只能包含指向常规实体的参考导航属性。
    • 实体不能包含无键实体类型的导航属性。

这意味着问题

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

您不能以这种方式修改数据-但是您可以读取。但是,人们可以设想使用另一种方式(例如ADO.NET,Dapper)来修改数据-这在您很少需要执行非读取操作而仍然希望在大多数情况下仍然坚持使用EF Core的情况下是一种解决方案。

此外,如果您确实需要/想要使用堆(无键)表,请考虑放弃EF并使用另一种方式与数据库进行通讯。

答案 12 :(得分:1)

这可能是迟到的回复...但是......

如果表没有主键,则需要分析的场景很少,以使EF正常工作。规则是:EF将使用具有主键的表/类。这就是它跟踪的方式......

说,你的桌子 1.记录是唯一的:唯一性由一个外键列: 2.记录是唯一的:唯一性由多列组合而成。 3.记录不是唯一的(大部分*)。

对于方案#1和#2,您可以将以下行添加到DbContext模块OnModelCreating方法: modelBuilder.Entity()。HasKey(x =&gt; new {x.column_a,x.column_b}); //尽可能多的列使记录唯一。

对于场景#3,您在学习表格后仍然可以使用上述解决方案(#1 +#2)(*无论如何都会使所有记录都是唯一的)。如果必须包含所有列以使所有记录唯一,那么您可能需要向表中添加主键列。如果此表来自第三方供应商,而不是将此表克隆到本地数据库(一夜之间或需要的时间),并通过克隆脚本任意添加主键列。

答案 13 :(得分:0)

我通过解决这个问题吸取了教训。简短的回答是不要解决它

我使用 EF6 读取没有 PK 但有复合键的表。具有相同复合键的多行将具有完全相同的记录。基本上只读取了一行,但用于填充所有行。由于记录数以百万计,而且只发生在相对较少的记录中,因此很难找到问题所在。

答案 14 :(得分:0)

在EF Core 5.0中,您也可以在实体级别进行定义。

[Keyless]
public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public int Zip { get; set; }
}

参考: https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew#use-a-c-attribute-to-indicate-that-an-entity-has-no-key

答案 15 :(得分:0)

我很高兴我的问题解决了。

Unable to update the EntitySet - because it has a DefiningQuery and no <UpdateFunction> element exist

然后执行以下操作: 在该行下面查找并找到标签。它将有一个很大的选择语句。删除标签及其内容。

现在无需更改DB T即可插入到没有PK的表中

全部感谢 并感谢Pharylon

答案 16 :(得分:0)

我们也遇到了这个问题,虽然我们有一个有空值的列,但重要的是我们有一个没有空值的依赖列,并且这两列的组合是唯一的。

所以引用Pratap Reddy给出的回应,它对我们来说很好。

答案 17 :(得分:0)

从实际的角度来看,每个表 - 甚至像仓库表一样的非规范化表 - 都应该有一个主键。或者,如果失败了,它至少应该有一个唯一的,不可为空的索引。

如果没有某种唯一键,重复记录可以(并且将会)出现在表中,这对于ORM层和基本理解数据都是非常有问题的。具有重复记录的表可能是设计错误的症状。

至少,该表至少应该有一个标识列。在SQL Server中添加自动生成ID列大约需要2分钟,在Oracle中需要5分钟。为了付出额外的努力,将避免许多许多问题。

答案 18 :(得分:-6)

该表只需要有一个不允许空值的列