Использование представления без первичного ключа с Entity
Я только начал работать над проектом, конвертирующим приложение из необработанного ADO.NET и встроенного SQL в Entity. Я столкнулся с проблемой с одним из видов, используемых приложением. В представлении нет первичного ключа и столбца (или комбинации столбцов), который однозначно идентифицирует строку. Вот выбор, созданный с помощью:
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):
FILINGMONTH CEIL(FILINGMONTH/3) LICNUM FILINGYEAR DECODE(GROUPING(INSURERNAME),'1','-ALLINSURED-',INSURERNAME) INSURERNAME POLICYLINECODE LINEDESCRIPTION SUM(NVL(GROSSPREMIUM,0)) SUM(DECODE(TAXEXEMPT,1,GROSSPREMIUM,0)) TRUNC(CASEWHEN(B.RSNISNOTNULLORA.ZEROREPORT=1)ANDB.DATERECEIVEDISNULLTHENA.DATERECEIVEDELSEB.DATERECEIVEDEND) SUM(AIP.ISCOMPANYADMITTED(B.NAICCOCODE,B.NAICALIENID)) INSUREDID
6 2 8150 2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO SAVERS PROPERTY AND CASUALTY INSURANCE CO 17 OTHER LIABILITY 721.25 0 18-JUL-07 0 81
6 2 8150 2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO SAVERS PROPERTY AND CASUALTY INSURANCE CO 17 721.25 0 18-JUL-07 0 81
6 2 8150 2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO SAVERS PROPERTY AND CASUALTY INSURANCE CO 721.25 0 18-JUL-07 0 81
6 2 8150 2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO SAVERS PROPERTY AND CASUALTY INSURANCE CO 721.25 0 18-JUL-07 0 81
insuredid является pk для таблицы aip.slbtransinsured, rsn является pk для aip.slbtransinsurer и aip.slblinecodes.
Можно ли вообще добавить представление к модели Entity без уникального идентификатора? Или есть простой способ добавить уникальный уникальный идентификатор строки в представление? Представление читается только, никогда не записывается в.
Ответы
Ответ 1
Можно ли вообще добавить представление к модели Entity без уникальный идентификатор?
Если без первичного ключа, нет. Это приведет к ошибке :
Во время генерации модели были обнаружены одна или несколько ошибок проверки:
System.Data.Edm.EdmEntityType:: EntityType 'SalesOnEachCountry' имеет ключ не определен. Определите ключ для этого EntityType. System.Data.Edm.EdmEntitySet: 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, Entity Framework производит этот неправильный вывод:
Country Year TotalSales
Philippines 2010 20.000000
Philippines 2010 20.000000
Entity Framework будет считать, что вторая строка - это тот же самый объект, что и первая строка.
Чтобы гарантировать уникальность, вы должны определить, какие столбцы делают каждую строку уникальной. В приведенном выше примере должен быть включен Год, поэтому первичный ключ уникален. т.е.
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 может правильно сопоставить каждую строку представления с собственными объектами. Следовательно, Entity Framework теперь может отображать те же строки, что и ваш вид.
Country Year TotalSales
Philippines 2010 20.000000
Philippines 2011 40.000000
Полная информация здесь: http://www.ienablemuch.com/2011/06/mapping-class-to-database-view-with.html
Затем, в отношении ваших представлений, которые не имеют столбцов, чтобы сделать уникальную строку, самым простым способом гарантировать, что Entity Framework может сопоставить каждую из строк вашего представления с их собственными объектами, является создание отдельного столбца для вашего первичного ключа вида, хорошим кандидатом является просто создать столбец номера строки в каждой строке. например.
create view RowNumberedView as
select
row_number() over(order by <columns of your view sorting>) as RN
, *
from your_existing_view
Затем назначьте атрибут [Key]
в свойстве RN вашего class RowNumberedView
Ответ 2
Расширение ответа Майкла Буэна:
Я обнаружил, что добавление номера строки в представление с помощью ISNULL() позволит инфраструктуре сущности вывести представление и автоматически создать необходимые данные EntitySet.
create view RowNumberedView as
select
ISNULL(ROW_NUMBER() OVER (ORDER BY <column>), 0) AS RN
, *
from your_existing_view
Ответ 3
Можно ли вообще добавить представление к модели Entity без уникального идентификатора?
Возможно иметь представления, в которых нет ни одного столбца или набора столбцов, которые создают первичный ключ; таким образом, вы оказываетесь в ложных отношениях. Таблицы хранилища данных иногда следуют этой форме. Короче говоря, нормализация иногда не соблюдается ни по причинам производительности, ни по причинам отчетности.
Теперь к вашему второму пункту:
Или есть простой способ добавить уникальный уникальный идентификатор строки в представление?
Я предлагаю вам выбрать все столбцы из slbtransinsured и посмотреть, можно ли найти один столбец, который однозначно идентифицирует каждую запись. Мне кажется, что в данных должен быть тип кода в 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;
Ответ 4
Поле счетчика строк может быть добавлено в представление для использования в качестве ключа.
См. ссылку .