实体框架 - 如何使用视图创建模型?

4
我对ASPNET和MVC 4完全不了解,因此我想这可能是一个简单的问题。但是,我一直无法在谷歌上找到答案。我只需要展示一些销售信息 - 我仅仅需要展示它。我不需要在底层表中插入、更新或删除任何内容。
有3个SQL Server表需要提取数据:CurrentSales、SalesPlans和AverageSales。我为此创建了一个VIEW,并在其上放置了一个唯一的聚集索引;它包含了一些外部连接,但有处理任何不太可能的NULL值的逻辑。
我进入MODELS,添加一个新的ADO.NET实体数据模型,并将我的视图添加到该模型中。结果返回并说:“表/视图'vw_FullView'没有定义主键。密钥已被推断,且定义为只读表/视图。” 当我从该模型和实体创建控制器类时,当我加载网站时,视图不显示任何数据。
然而,如果我创建一个完全空白的表 - 具有适当的主键 - 作为模型表,然后使用存储过程(作为函数导入)来检索所需的数据,那么一切都可以正常工作。
这显然不能是正确处理此问题的方法。是否有一种方法可以从视图中创建强类型模型?我更希望在ASP.NET中自动生成控制器和视图对象,而不需要这个空白表来“愚弄”系统。
提前感谢你的帮助。

请展示此问题的操作和视图(cshtml):“当我从此模型和实体创建控制器类时,加载网站时视图不显示任何数据。” - AaronLS
Aaron - 我仔细检查了一遍,似乎我实际上可以在我的MVC视图中访问由SQL视图模型对象生成的对象,但它不干净地进入并且格式不好看。我将采用下面的解决方案之一并重新编码。谢谢! - Skkra
3个回答

4

Entity framework并不喜欢视图。它无法确定视图的主键,因此假设任何非空字段都是组合主键的一部分。

通常情况下,在使用Entity Framework时应避免使用视图。创建一个linq查询来完成视图的操作,并使用该查询代替视图。


问题在于,如果您从另一个数据库中提取数据,则应该需要视图。EF一次只查看一个数据库,但使用视图可以获取信息。 - sksallaj
@sksallaj - 不要使用视图来实现。使用Sql Server Synonyms。您可以像普通表一样创建Code First模型,并且它们的工作方式就像表格一样,而不是视图。对于edmx文件来说可能会更难,但仍然可以完成。 - Erik Funkenbusch
你如何将同义词添加到实体框架中?我有同义词,但它根本没有被识别。事实上,我认为这是一个请求的 EF 功能,但从未被实现。 - sksallaj
还是只限于SQL Server?我正在使用Oracle,有多个模式..如果我使用视图,它会变成只读,因为它无法正确识别主键。 - sksallaj
@sksallaj - 我没意识到你在使用Oracle。我不知道同义词在Oracle中如何工作。在Sql Server中,EF只是将它们用作表格。当使用edmx文件时,设计师不支持它们的本地支持,但有办法绕过这个问题。Code First更容易。 - Erik Funkenbusch
啊,我明白了,是的,Oracle目前还不支持Code First。这就是为什么在我的情况下视图效果最好的原因;当你使用视图时,唯一发生的事情就是你不能对其进行更新或插入操作,此时它变成了只读表。 - sksallaj

2
确实,Entity Framework对SQL Server视图并不友好,因为在视图中主键不明显。不幸的是,在模型中指定[Key]似乎不足够。然而,在98%的情况下,这可以实现,并且非常有用,因为它能够将多个表组合起来,仅仅是为了在网格中显示数据。关键(请原谅我用词不当)是要正确定义视图。
我的原始视图包含以下列:
DepartmentCode(varchar(8),not null)
DepartmentName(varchar(60), not null)
DivisionCode(varchar(8), null)
DivisionName(varchar(8), null)
StatusCode(char(1), not null)
Virtual(varchar(1), not null)

在我的模型中,我指定了


[Key]
[Column("DepartmentCode")]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[StringLength(8)]
[Display(Name = "Department Code")]
public string DepartmentCode { get; set; }

当我搭建这个并显示索引视图时,出现了一个涉及主键的错误。显然,Entity Framework假定所有非空字段都对主键有贡献。
移除额外的非空字段就解决了问题。我使用以下方法强制将视图中的列设为可为空:
CREATE view [dbo].[Departments] as
select DepartmentCode
,nullif(DepartmentName,'') as DepartmentName
,nullif(DivisionCode,'') as DivisionCode
,nullif(DivisionName,'') as DivisionName
,nullif(StatusCode,'') as StatusCode
,nullif(Virtual,'') as Virtual
from ....

现在视图列看起来像这样。
DepartmentCode(varchar(8),not null)
DepartmentName(varchar(60), null)
DivisionCode(varchar(8), null)
DivisionName(varchar(8), null)
StatusCode(char(1), null)
Virtual(varchar(1), null)

一旦我更改了视图,Index视图就可以正常工作。

我还确认一个包含复合(多列)键的视图也可以正常工作,只要这些列不为空并且在您的模型中指定每个列上的[Key],并且在这些关键列的[Column]注释中添加Order=1和Order=2。

当然,这里的假设是您有权限修改视图(或可以创建替代视图)。 我只能确认这适用于MVC 5和Entity Framework 6。


1

视图只是实体或实体组合的投影。默认情况下,Entity Framework 只允许只读访问,因为视图中没有真正的实体,即 ET 无法跟踪更改。

Simmdan 实际上很好地解释了如何解决这个问题,在 MSDN 论坛 中。

基本上,就像 Mystere Man 已经指出的那样,如果您使用 Entity Framework,最简单的方法是使用 Linq 连接并过滤真实的实体来克隆视图。


我明白了。由于各种业务限制,我试图避免使用LINQ,并通过存储在SQL中的存储过程来处理/映射所有内容。我想我必须找到一个解决方法,或者干脆接受并使用LINQ。 - Skkra
顺便提一下,您可以使用默认的SQL连接并直接操作存储过程来读取/更新视图。 - Ingo
@Skkra - 如果您不想使用LINQ,那么为什么要使用Entity Framework呢? - Erik Funkenbusch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接