Sql 在实体中使用没有主键的视图
我刚刚开始一个项目,将应用程序从原始ADO.NET和嵌入式SQL转换为实体。我遇到了应用程序使用的一个视图的问题。视图没有唯一标识行的主键和列(或列组合)。以下是创建视图时使用的选项:Sql 在实体中使用没有主键的视图,sql,oracle,entity,Sql,Oracle,Entity,我刚刚开始一个项目,将应用程序从原始ADO.NET和嵌入式SQL转换为实体。我遇到了应用程序使用的一个视图的问题。视图没有唯一标识行的主键和列(或列组合)。以下是创建视图时使用的选项: SELECT filingmonth, CEIL(filingmonth / 3), licnum, filingyear, DECODE(GROUPING(insurername), '1', '- All Insured -', insurername), in
SELECT
filingmonth,
CEIL(filingmonth / 3),
licnum,
filingyear,
DECODE(GROUPING(insurername), '1', '- All Insured -', insurername),
insurername,
policylinecode,
linedescription,
SUM(NVL(grosspremium, 0)),
SUM(DECODE(taxexempt, 1, grosspremium, 0)),
TRUNC(
CASE
WHEN
(
b.rsn IS NOT NULL
OR A.zeroreport = 1
)
AND b.datereceived IS NULL
THEN A.datereceived
ELSE b.datereceived
END),
SUM(aip.iscompanyadmitted(b.naiccocode, b.naicalienid)),
A.insuredid
FROM
aip.slbtransinsured A
LEFT OUTER JOIN aip.slbtransinsurer b
ON
A.insuredid = b.insuredid
LEFT OUTER JOIN aip.slblinecodes C
ON
b.policylinecode = C.linecode
WHERE
A.submitted = 1
AND A.entryincomplete = 0
GROUP BY
licnum,
filingmonth,
filingyear,
TRUNC(
CASE
WHEN
(
b.rsn IS NOT NULL
OR A.zeroreport = 1
)
AND b.datereceived IS NULL
THEN A.datereceived
ELSE b.datereceived
END),
ROLLUP(insurername, aip.iscompanyadmitted(b.naiccocode, b.naicalienid),
policylinecode, linedescription), A.insuredid;
下面是一些示例数据,显示有些行完全重复(第3行和第4行):
insuredid是aip.slbtransserved表的主键,rsn是aip.slbtransserver和aip.slblinecode的主键
是否可以在没有唯一标识符的情况下向实体模型添加视图?或者有没有一种简单的方法可以将唯一的行标识符添加到视图中?视图仅从中读取,从不写入
是否可以在没有唯一标识符的情况下向实体模型添加视图
可以在没有创建主键的单个列或一组列的视图中创建主键;因此,你最终会有虚假的关系。数据仓库表有时遵循这种形式。简而言之,出于性能原因或报告原因,有时不遵循规范化
现在谈谈你的第二点:
或者有没有一种简单的方法可以将唯一的行标识符添加到视图中
我建议您做的是从slbtransaured中选择所有列,并查看是否可以找到唯一标识每个记录的列。在我看来,在slblinecodes中应该有一个需要选择的代码类型,有点像查找
要想玩得开心,试着运行这个,告诉我你得到了什么:
SELECT filingmonth,
CEIL (filingmonth / 3),
licnum,
filingyear,
DECODE (GROUPING (insurername), '1', '- All Insured -', insurername),
insurername,
policylinecode,
linedescription,
SUM (NVL (grosspremium, 0)),
SUM (DECODE (taxexempt, 1, grosspremium, 0)),
TRUNC (
CASE
WHEN (b.rsn IS NOT NULL OR a.zeroreport = 1)
AND b.datereceived IS NULL
THEN
a.datereceived
ELSE
b.datereceived
END),
SUM (aip.iscompanyadmitted (b.naiccocode, b.naicalienid)),
a.insuredid
FROM aip.slbtransinsured a
LEFT OUTER JOIN aip.slbtransinsurer b
ON a.insuredid = b.insuredid
LEFT OUTER JOIN aip.slblinecodes c
ON b.policylinecode = c.linecode
WHERE a.submitted = 1 AND a.entryincomplete = 0
GROUP BY filingmonth,
licnum,
filingyear,
DECODE (GROUPING (insurername), '1', '- All Insured -', insurername),
insurername,
policylinecode,
linedescription,
TRUNC (
CASE
WHEN (b.rsn IS NOT NULL OR a.zeroreport = 1)
AND b.datereceived IS NULL
THEN
a.datereceived
ELSE
b.datereceived
END),
a.insuredid;
是否可以将视图添加到实体模型而不使用
唯一标识符
如果没有主键,则不会。这将导致此类:
在模型生成过程中检测到一个或多个验证错误:
System.Data.Edm.EdmEntityType::EntityType“SalesOnEachCountry”具有
没有定义键。定义此EntityType的键。
System.Data.Edm.EdmentySet:EntityType:EntitySet
SalesOnEachCountryList基于类型SalesOnEachCountry,该类型没有
已定义关键点
如果没有唯一标识符,则为“是”,尽管输出不理想。具有相同标识符的记录将引用相同的对象,这称为
例如,即使视图生成以下两行:
Country Year TotalSales
Philippines 2010 20.000000
Philippines 2011 40.000000
如果仅将主键映射到国家/地区字段,例如
public class SalesOnEachCountry
{
[Key]
public int CountryId { get; set; }
public string CountryName { get; set; }
public int OrYear { get; set; }
public long SalesCount { get; set; }
public decimal TotalSales { get; set; }
}
,即使您的视图在Oracle查询编辑器上生成上述两行,实体框架也会生成不正确的输出:
Country Year TotalSales
Philippines 2010 20.000000
Philippines 2010 20.000000
实体框架将认为第二行是和第一行相同的对象
为了保证唯一性,您必须确定使每一行唯一的列。在上面的示例中,必须包含年份,以便主键是唯一的。i、 e
public class SalesOnEachCountry
{
[Key, Column(Order=0)] public int CountryId { get; set; }
public string CountryName { get; set; }
[Key, Column(Order=1)] public int OrYear { get; set; }
public long SalesCount { get; set; }
public decimal TotalSales { get; set; }
}
通过使主键与上述属性相似,Entity Framework可以将每个视图的行正确映射到它们自己的对象。因此,EntityFramework现在可以显示与视图完全相同的行
Country Year TotalSales
Philippines 2010 20.000000
Philippines 2011 40.000000
详情如下:
然后,对于没有任何列使行唯一的视图,确保Entity Framework可以将视图的每一行映射到其自己的对象的最简单方法是为视图的主键创建一个单独的列,一个好的候选方法是在每一行上创建一个行号列。e、 g
create view RowNumberedView as
select
row_number() over(order by <columns of your view sorting>) as RN
, *
from your_existing_view
创建视图行编号视图为
挑选
(订货人)上方的行号()为RN
, *
从您的现有视图
然后在
类RowNumberedView的RN属性上指定[Key]
属性
在使用视图时考虑使用AsNoTracking()。这将禁止使用任何关键字段进行EF跟踪。然后,可以手动将任何非空字段定义为EF键(即使重复)
建议不要创建额外的行计数器字段,因为大多数行计数器最终都要求引擎扫描视图的整个域以生成正确的计数器值,即使使用谓词(where子句)进行查询也是如此
请参阅。扩展Michael Buen的答案: 我发现,使用ISNULL()将行号添加到视图将允许实体框架拉入视图并自动创建必要的EntitySet数据
create view RowNumberedView as
select
ISNULL(ROW_NUMBER() OVER (ORDER BY <column>), 0) AS RN
, *
from your_existing_view
创建视图行编号视图为
挑选
ISNULL(按(ORDER BY)上的行号()为0)作为RN
, *
从您的现有视图
最近在工作中,我遇到了同样的问题。根据我的研究,我找不到任何关于如何在没有PK的情况下将视图附加到EF6 CodeFirst的答案。大多数似乎都涉及迁移,而且相当混乱。我相信DB first对工作SQL视图
有更好的支持
我确实尝试过引入一个窗口函数(RowNumber),其思想是,使用行标识符作为主键,以使EF6满意。但这使得我的查询总体上更加昂贵,所以我不得不放弃这个想法
最后,我不得不仔细分析我的数据集,看看是否可以引入一个复合键——它涵盖了我的业务应用程序需要确保工作的所有场景。记住也要使用IsNull(ColumnName,0)
,以确保能够满足CodeFirst fluent方法中的.IsRequired()
i、 e
我希望这对某些人有所帮助-对我来说,答案是分析数据集,视图反规范化并寻找复合键
如果您在ASP.NET中使用实体框架和MVC,您可以尝试另一个很酷的想法。
如前所述,使用具有自动递增或行号的列创建视图。
假设您有该列,它的名称是rowNumber
在MVC应用程序的Models
目录中,要转到上下文文件(yourDatabaseNameContext
)文件,请查找视图的定义,而不是
modelBuilder.Entity<yourView>(entity =>
{
entity.HasNoKey();
HasKey(x => new { x.KfiId, x.ApplicationNumber, x.CustomerId });
modelBuilder.Entity<yourView>(entity =>
{
entity.HasNoKey();
modelBuilder.Entity<yourView>(entity =>
{
entity.HasKey(e => e.rowNumber);