实体框架:表没有主键

实体框架:表没有主键

问题描述:

我有一个现有的分贝,我想使用EF4.0实体框架:表没有主键

一些表没有定义主键,这样,当我创建一个新的实体,以建立一个新的应用程序数据模型中,我收到以下消息:“表/视图TABLE_NAME没有定义主键,并且没有有效的主键可以被推断出来,这个表/视图已经被排除了,要使用这个实体,你需要检查你的架构,添加正确的密钥,并取消注释“。

如果我想使用它们并修改数据,我必须向这些表添加一个PK,还是有解决方法,以便我不必?

+19

引用Joe Celko:*如果它没有主键,则不是表*。为什么人人都会创建一个没有主键的“常规”表?只需添加那些PK!你会需要他们 - 而不是晚于... – 2010-10-22 12:55:22

+2

+1即使你引用celko ;-) – 2010-10-22 13:19:32

+4

如果它的一个视图这个哈瓦看起来这个案例http://stackoverflow.com/a/10302066/413032 – 2012-04-24 16:32:43

错误的含义正是它所说的。

即使你能解决这个问题,相信我,你不想。可能引入的令人困惑的错误数量惊人而可怕,更不用说您的性能可能会下降。

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

编辑:我见过很多人都在回答这个问题。我想这很好,但请记住,OP询问了如何映射没有主键,而不是视图。答案依然如此。从可管理性,数据完整性和性能的角度来看,解决EF需要对表进行PK是个坏主意。

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

+34

同意常见senarios,但在罕见的senarios像LOG表,你只需要尽快插入记录。在检查唯一性和编制索引时发生PK可能是一个问题。另外如果你的PK是IDENTITY,那么将生成的值返回给EF是另一个问题。使用GUID呢?世代时间和索引/排序是另一个问题!...所以在没有PK的一些重要OLTP senarios(如Logging)中,这是一个观点,并且它没有任何正面的观点! – 2012-01-29 22:18:47

+3

@MahmoudMoravej:首先,不要混淆聚类索引和主键的想法。他们不是一回事。您可以在IDENTITY列上具有聚簇索引的表上进行非常高性能的插入。如果遇到索引维护问题,则应正确分区表。留下没有聚集索引的表格也意味着您不能有效地对其进行碎片整理,以便在删除后回收空间。我怜悯那些试图查询日志表的人,如果它没有索引的话。 – 2012-01-30 04:08:54

+1

感谢Dave,你让我重新思考:-)。我不知道我们可以拥有非群集PK(虽然它的性能比clusterd-one少于唯一性检查,不是吗?特别是在IDENTITY PK当新的插入将被放在表空间的末尾)。 – 2012-01-30 11:16:04

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

但是,如果有一个,但它只是没有指定与数据库中的索引,并且你不能改变数据库(是的,我在迪尔伯特的世界工作),你可以手动映射领域(S)是钥匙。

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

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

埃里克

+0

这可以避免ISNULL破解。但根据情况,可能需要其他答案 - 例如,我有一种感觉,某些数据类型不支持EF中的PK。 – Todd 2014-10-11 03:35:09

我认为这是由Tillito解决:

Entity Framework and SQL Server View

我引用下面的他项:

我们有同样的问题,这是解决方案:

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

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

一个简单的方法来运用,这是包装视图的select语句的另一个选择。

实施例:

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

回答年04月26 '10在17:00由Tillito

+33

实际回答问题。 – TheSmurf 2012-11-26 21:38:03

+6

+1这是正确的答案,在一个完美的世界中,进入并修改所有遗留数据库以具有参照完整性是非常好的,但实际上并非总是可行。 – 2013-05-01 17:48:32

+7

我不会推荐这个。特别是ISNULL部分。如果EF检测到两个相同的PK,它可能不会呈现唯一记录,而是返回一个共享对象。这发生在我以前。 – Todd 2013-08-19 03:17:15

  1. 改变表结构,并添加一个主列。更新模型
  2. 修改XML编辑器中的.edmx文件,并尝试在标签中添加一个新列这个特定表而不是创建一个新的主列于表退出的(无效)
  3. ,我会 做通过涉及所有现有的列组合键(保护正常工作

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

+0

我尝试了EF 4.0的组合键方法,但没有奏效。 – 2012-08-23 15:16:10

+0

这种方法对我来说是完美的,可能是一个与遗留系统“有时”工作的痛苦...... – pinmonkeyiii 2014-05-30 21:42:53

表只需要有一列不允许为空

拥有无用的身份密钥有时毫无意义。我发现如果ID不被使用,为什么添加它?然而,实体并不那么宽容,所以添加一个ID字段将是最好的。即使在未使用的情况下,它也比处理Entity关于丢失的身份密钥的不间断错误要好得多。

此解决方案

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

要做到这一点,你可以添加行号,以你的观点与ISNULL函数类似下面的

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

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

+2

虽然我不会建议ISNULL部分。如果EF检测到两个相同的PK,它可能不会呈现唯一记录,而是返回一个共享对象。这发生在我以前。 – Todd 2013-08-19 03:15:52

+1

您必须使用isnull,否则EF将不会承认它不为空。 – Archlight 2014-02-25 15:19:34

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

没有某种独特的键,重复的记录可以(将)在表中出现,这既是对ORM层,也为数据的基本理解很成问题。具有重复记录的表格可能是不良设计的症状。

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

+0

我的应用程序位于数据仓库设置(使用Oracle),并且您说服我通过5分钟来添加索引。它只需要5分钟(或稍多,如果你需要[查看](http://stackoverflow.com/questions/11464396/add-a-auto-increment-primary-key-to-existing-table- in-oracle)或修改ETL)。 – Trent 2016-01-20 18:36:48

我们遇到了这个问题为好,虽然我们有一个列有空,重要的是,我们必须说没有空,并且这两列的组合是独一无二的依赖列。

所以要引述普拉塔普·雷迪作出的反应,这对我们工作的罚款。

在我来说,我有一个实体映射到一个视图,它不具有主键。而且,我不允许修改这个视图。 幸运的是,这个视图有一列是唯一的字符串。我的解决方案是将此列标记为主键:

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

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

+0

否..如果您使用Code First方法,它将创建'UserID'列。 – 2014-10-22 18:05:44

+1

你没有骗过EF。你只是命令关闭'Itentity'功能。基本上,如果我是正确的,它仍然会为你创建'UserID'列作为PK,但是当你创建一个新记录时它不会自动增加'UserID',因为它是默认的。另外,您仍然需要在'UserID'中保留不同的值。 – Celdor 2015-01-27 10:56:35

+0

@Celdor UserSID是一个字符串,它永远不会“自动增加”。如果它是一个整数标识列,那么数据库将在插入时增加它,而不是实体框架。 – reggaeguitar 2017-07-07 16:03:27

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

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

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

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

组合键也可以与实体框架流利API

public class MyModelConfiguration : EntityTypeConfiguration<MyModel> 
{ 
    public MyModelConfiguration() 
    { 
     ToTable("MY_MODEL_TABLE"); 
     HasKey(x => new { x.SourceId, x.StartDate, x.EndDate, x.GmsDate }); 
     ... 
    } 
} 
+0

在这种'手动映射'的情况下,我发现在显示时指定一个自定义键是有效的;此外,如果您没有组合键的好处(如本答案中所示),您可以使用'.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)'标记一个'modelBuilder.Entity ()'链式调用'非自然或复合的特殊密钥,但能够依靠它们是唯一的(通常,无论如何)。 – 2017-01-27 22:48:17

这可能是后期做了回答。不过......

如果表简化版,有一个主键然后为了使EF正常工作,需要分析的场景很少。规则是:EF将与主键一起使用表/类。这就是它如何跟踪...

说,你的表 1.记录是唯一的: 2.记录是唯一:唯一性是由单一外键列做出的独特的组合制成多列。 3.记录不是唯一的(大部分*)。

对于场景#1和#2可以添加下面的行的DbContext模块OnModelCreating方法: modelBuilder.Entity()HasKey(X =>新的{x.column_a,x.column_b}); //使记录具有唯一性所需的列数。

对于场景#3,在研究表(*无论如何都使所有记录独一无二)后仍然可以使用上述解决方案(#1 +#2)。如果您必须包含所有列才能使所有记录具有唯一性,那么您可能需要将主键列添加到您的表中。如果此表来自第三方供应商,则将该表克隆到本地数据库(隔夜或需要多少时间),并通过您的克隆脚本随意添加主键列。