2012-07-06 21 views
14

acabo de empezar en un proyecto de conversión de una aplicación de ADO.NET y SQL incrustado en bruto a la Entidad. Me encontré con un problema con una de las vistas utilizadas por la aplicación. La vista no tiene clave principal ni columna (o combinación de columnas) que identifique una fila de manera única. Aquí está el seleccionar la vista se crea con:Usando una vista con ninguna clave primaria con Entidad

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; 

Y aquí es algunos datos de ejemplo que muestran que hay algunas filas que están completamente duplicada (filas 3 y 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 es la pk para la tabla aip.slbtransinsured, RSN es el pk para aip.slbtransinsurer y aip.slblinecodes.

¿Es del todo posible agregar la vista el modelo Entidad sin un identificador único? ¿O hay una manera fácil de agregar un identificador de fila único a la vista? La vista solo se lee, nunca se escribe.

Respuesta

23

¿Es del todo posible agregar la vista el modelo Entidad sin un identificador único ?

Si no tiene una clave principal, no. Que dará lugar a este tipo de error: se detectaron

uno o más errores de validación durante la generación del modelo:

System.Data.Edm.EdmEntityType:: EntityType 'SalesOnEachCountry' tiene ninguna tecla definida. Defina la clave para este EntityType. System.Data.Edm.EdmEntitySet: EntityType: EntitySet SalesOnEachCountryList se basa en el tipo SalesOnEachCountry que no tiene definidas las claves .

Si sin un identificador único, sí, aunque tiene un resultado no deseable.Los registros con mismo identificador haría referencia al mismo objeto, esto se llama Identity Map Pattern

Un ejemplo, aunque su vista produce estas dos filas:

Country  Year TotalSales 
Philippines 2010 20.000000 
Philippines 2011 40.000000 

Si usted acaba de asignar la clave principal en el campo de país solamente, p.ej

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; } 
} 

, incluso su vista produce las dos filas por encima de su editor de consultas de Oracle, Entity Framework produce esta salida incorrecta:

Country  Year TotalSales 
Philippines 2010 20.000000 
Philippines 2010 20.000000 

Marco de la entidad se entenderá que la segunda fila es el mismo objeto como primera fila.

Para garantizar la exclusividad, debe identificar qué columnas hacen que cada fila sea única. En el ejemplo anterior, se debe incluir Year, por lo que la clave principal es única. es decir,

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; } 
} 

Haciendo fila su clave primaria similar a los atributos anteriores, Entity Framework puede asignar correctamente su cada de vista de sus propios objetos. Por lo tanto, Entity Framework ahora puede mostrar exactamente las mismas filas que tiene su vista.

Country  Year TotalSales 
Philippines 2010 20.000000 
Philippines 2011 40.000000 

Todos los detalles aquí: http://www.ienablemuch.com/2011/06/mapping-class-to-database-view-with.html


A continuación, con respecto a sus puntos de vista que no tienen ninguna columna para hacer una fila única, la forma más fácil de garantizar Entity Framework puede asignar cada uno de la fila de la vista a sus propios objetos es crear una columna separada para clave principal de su vista, un buen candidato es simplemente crear una columna de número de fila en cada fila. p.ej.

create view RowNumberedView as 

select 
    row_number() over(order by <columns of your view sorting>) as RN 
    , * 
from your_existing_view 

A continuación, asigne el atributo [Key] la RN propiedad de su campo contador class RowNumberedView

+0

Gracias por esto, realmente me ayudaste. Estoy trabajando con tablas de Oracle que no tienen una columna de ID única visible y estaba empezando a desesperar porque LINQ estaba devolviendo la misma fila. Seguí tu sugerencia acerca de crear mi propia clave en la clase Entity y funciona perfectamente. – markp3rry

+1

Creo que agregar un guid a la proyección es más eficiente. En las vistas con campos de datos binarios, he encontrado que (orden por ) ralentiza la consulta. ¿Hay algún problema con este enfoque?Por ejemplo: SELECT NEWID() AS PrimaryKey, FROM View –

+0

Sin embargo, hay una manera de obtener una vista agregada como una "entidad de solo lectura" sin clave primaria si usa Database-first Entity Framework. Incluso obtiene [un error claro] (http://stackoverflow.com/questions/24792259/error-6002-the-table-view-does-not-have-a-primary-key-defined) cuando agrega una vista sin una clave obvia que indique que EF está ** obligando ** a su entidad a ser una entidad sin llave de solo lectura. Seguramente hay una manera de duplicar esto usted mismo? – ruffin

0

¿Es posible agregar una vista al modelo de entidad sin un identificador único?

Es posible tener una vista donde no haya una sola columna o conjunto de columnas que creen la clave principal; por lo tanto, terminas con relaciones falsas. Las tablas del depósito de datos a veces siguen esa forma. En resumen, a veces la normalización no se cumple por razones de rendimiento o por razones de informes.

Ahora con su segundo punto:

O hay una manera fácil de agregar un identificador de fila única a la vista?

Lo que sugiero que haga es seleccionar todas las columnas de slbtransinsured y ver si puede encontrar la columna única que identifica cada registro. Me parece que los datos que hay allí deberían ser un tipo de código en códigos slbline que debe seleccionar, algo así como una búsqueda.

por diversión, intente ejecutar esto y dime lo que se obtiene:

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; 
+0

Gracias, pero no le gusta la función GROUPING en la cláusula GROUP BY. La única columna única en slbtransinsured es su clave principal, insuredid, que se duplica en la vista. No hay relación entre slbtransinsured y slblinecodes, solo entre slbtransinsurer y slblinecode. –

0

Una fila puede añadirse a la vista para usar como clave.

Por favor, vea link.

12

Ampliando la respuesta de Michael Buen: Encontré que agregar el número de fila a la vista con un ISNULL() permitirá que la estructura de la entidad arrastre la vista y cree los datos necesarios de EntitySet automáticamente.

create view RowNumberedView as 

select 
    ISNULL(ROW_NUMBER() OVER (ORDER BY <column>), 0) AS RN 
    , * 
from your_existing_view 
+0

Esto no funciona para mí, ya puse row_number pero sigo sin recuperar la vista en mi EntitySet – csuazo

Cuestiones relacionadas