2012-02-23 18 views
11

¿Hay alguna forma de marcar una entidad como de solo lectura y no especificar ninguna clave para ella?Código Entity Framework First ReadOnly Entity

+0

Código Primera toda la entidad a ser de sólo lectura y sólo lectura son un poco mutuamente excluyentes. Solo por curiosidad, ¿por qué no quieres una clave principal? – Brian

+1

Enttity se asigna a una vista y no quiero actualizar/insertar en él, y tampoco tengo ninguna clave. – Otake

+0

EF no hará actualizaciones en las vistas de manera predeterminada. –

Respuesta

11

Hay un par de cosas que puede hacer para aplicar solo lectura en Code First. El primero es usar AsNoTracking() cuando realiza una consulta.

var readOnlyPeople = (from p in context.People 
         where p.LastName == "Smith" 
         select p).AsNoTracking(); 

Esto le dice al primer Código no registrar los cambios a estas entidades, por lo que cuando se llama a SaveChanges() no hay cambios realizados en estos objetos se conservará.

La segunda cosa que puede hacer es establecer el estado en Unchanged antes de llamar al SaveChanges().

context.Entry(person).State = EntityState.Unchanged; 
context.SaveChanges(); 

Esto le dice a Code First que ignore los cambios que se hayan realizado en esa entidad.

En cuanto a no tener una clave, todas las entidades deben tener una clave. Esto no necesariamente se correlaciona con una clave principal en la base de datos, sino que "debe identificar de forma única una instancia de tipo de entidad dentro de un conjunto de entidades".

+2

Hola Brice, tus sugerencias no son soluciones ideales para mí (realmente preferiría simplemente marcar esa entidad como de solo lectura, que existe en NH) pero no creo que lo que deseo sea posible con una solución clara en EF todavía. Según "todas las entidades deben tener una clave", estoy de acuerdo con usted, pero a veces tiene que trabajar con algunas vistas y no tienen ninguna clave y si puedo marcar una entidad como de solo lectura, ¿por qué debería necesitar una clave? . – Otake

+0

En realidad, puede utilizar una interfaz de marcador IReadOnlyEntity similar a la interfaz ICacheableEntity que se sugiere aquí (También hay publicaciones de blog que describen esto, cuando encontré el código originalmente, pero no pude encontrarlo) http://stackoverflow.com/a/ 6593261/34474 Hay algunos problemas con las relaciones entre ellos que debes tener en cuenta (si alguien está interesado, házmelo saber). Al final, estamos haciendo lo que Brice sugirió solo de una manera más automatizada. – Cohen

+0

Si su vista no tiene una clave natural, puede agregar una para ayudar a EntityFramework. En la definición de vista: SELECT \t NEWID() como [VirtualKey] ... En Mapa de la Entidad: // clave principal this.HasKey (t => t.VirtualKey); – Elton

8

Al usar código primero en EF6, creé algunas entidades que reflejan Vistas, que obviamente no deberían modificarse ni guardarse. Para evitar que la Entidad sea cambiada, solía protegido propiedades de deformación:

public class TransplantCenterView 
{ 
    public string TransplantsThisYear { get; protected set; } 
} 

Marco de la entidad sigue siendo capaz de establecer esta propiedad, pero otros desarrolladores no pueden accidentalmente hacerlo sin un error en tiempo de compilación. Esto funciona muy bien, pero parece que la mejor solución sería eliminar el seguimiento por completo.


Gracias a reggaeguitar's answer, parece que hay una respuesta a esto (por favor, también votar su respuesta a si el siguiente es útil), que me ha permitido cambiar el código de:

public class MyContext : DbContext 
{ 
    public DbSet<TransplantCenterVeiw> TransplantCenterViews {get; set;} 
} 

a:

public class MyContext : DbContext 
{ 
    //appears the DbSet is still needed to make Set<Entity>() work 
    protected DbSet<TransplantCenterView> _transplantCenterViews {get; set;} 
    //this .AsNoTracking() disables tracking for our DbSet. 
    public DbQuery<TransplantCenterView> TransplantCenterViews { 
     get { return Set<TransplantCenterView>().AsNoTracking(); } 
    } 
} 

no sé de ningún pros y contras para esto, pero mi código existente ha seguido trabajando de manera impecable, por lo que parece una victoria.

+0

Consulte mi respuesta para obtener una forma de deshabilitar el seguimiento en la entidad. – reggaeguitar

+0

Devs _debería seguir llamando a MyContext.Set (). DoAnyThing(), por lo que aún prefiero su solución de 'conjunto protegido'. –

1

Si se desea se puede hacer esto

/// Using a dbquery since this is readonly. 
/// </summary> 
public DbQuery<State> States 
{ 
    get 
    { 
    // Don't track changes to query results 
    return Set<State>().AsNoTracking(); 
} 
} 

fuente http://www.adamtuliper.com/2012/12/read-only-entities-in-entity-framework.html

+4

Cambió DbSet a DbQuery. Cambió el getter a como se describe arriba. Compilado. Todo bien. Sin embargo, cuando voy a ejecutar la página que carga los datos de la vista, aparece un error de tiempo de ejecución: "El tipo de entidad' MyEntityName' no es parte del modelo para el contexto actual ". Por lo tanto, agregó 'DbSet protegido _hiddenMyEntitiesName {get; set;} 'y luego las cosas funcionaron. Valdría la pena agregar el DbSet <> en el código anterior para que las personas no se encuentren con la misma confusión ... ¿o si hay otra manera? Pero gracias por ponerme en el camino correcto. –

+0

Interesante, no recibí ese error. Estoy mapeando tablas y no vistas, ¿tal vez esa es la diferencia? – reggaeguitar

+0

Hmm ... entonces, ¿no tiene una propiedad DbSet en cualquier parte de su contexto, y todavía funciona? Extraño ... también podría ser un problema de versión. Estoy de vuelta en VS 2015 y EF6. –

Cuestiones relacionadas