2012-10-09 76 views
6

Tengo un problema interesante que resolver, pero, aunque es común, parece que no se puede lograr fácilmente con Entity Framework. Hay dos tablas:Entity Framework - Propiedad de solo lectura de la entidad asignada a una columna de la tabla relacionada

Player(Id,TeamId,FirstName,LastName) 
Team(Id, Name, IsProfessional) 

El jugador solo puede pertenecer a un equipo. El uso de TPT (DB primero), tenemos dos clases asignada a esas tablas:

public class Player 
{ 
    public int Id{get;set;} 
    public int TeamId{get;set;} 
    public string FirstName{get; set;} 
    public string LastName{get; set;} 
    public Team Team{get;set;} 
} 

public class Team 
{ 
    public int Id{get; set;} 
    public string Name{get;set;} 
    public bool IsProfessional{get;set;} 
    public IEnumerable<Player> Players{get;} 
} 

Lo que me gustaría lograr es propiedad IsProfessional en la entidad del jugador:

public class Player 
    { 
     public int Id{get;set;} 
     public int TeamId{get;set;} 
     public string FirstName{get; set;} 
     public string LastName{get; set;} 
     public Team Team{get;set;} 
     **public bool IsProfessional{get;}** should be read-only 
    } 

¿Es posible configurar la asignación que manera en que la propiedad IsProfessional se puede usar en consultas linq?

var result= db.Players.Where(p=>p.IsProfessional==true); 

y tener ese campo poblado cada vez que se materializa la entidad de jugador?

Player pl = db.Players.Where(p=>p.FirstName="Lionel").FirstOrDefault(); 
if(pl.IsProfessional) 
{ 
//do something... 
} 

intentado ya con:

  • Entidad División. No es posible porque quiero mantener el mapeo del equipo y porque la relación no es 1: 1)
  • Mapeo de la entidad del jugador a una vista de db. No me gustó porque hay otras relaciones que la entidad del jugador tiene que necesito. Sé que es posible crearlos manualmente, pero la actualización de edmx desde la base de datos restablecerá ssdl.

Gracias

Solución

Basado en segunda opción en Gert Arnold respuesta, solución que se adapte a mis necesidades es la siguiente:

  1. puedo crear la función GetIsProfessional (tenía que hágalo porque los campos calculados normalmente solo se pueden hacer desde los campos de la tabla propia)

    CREATE FUNCTION [dbo].[GetIsProfessional](@teamId as INT) 
    RETURNS bit 
    
    BEGIN 
    
    DECLARE @isProfi AS bit 
    
    SELECT @isProfi = IsProfessional 
    FROM Teams 
    WHERE Id = @teamId 
    
    RETURN @isProfi 
    
    END 
    
  2. creé campo calculado en Player mesa

    ALTER TABLE Players ADD [IsProfessional] AS dbo.GetIsProfessional(TeamId) 
    
  3. Como estoy usando primera aproximación db, acabo de actualización del modelo de base de datos y eso es todo, puedo consultar en ese campo y es pre poblada cuando el objeto Player se materializa.

+0

Entonces 'Player.IsProfessional' debe dar el mismo resultado que' Player.Team.IsProfessional'? Actualmente, EF no admite propiedades que no se asignan a un campo de base de datos simple, lo siento, pero tal vez alguien responderá con una buena alternativa. – hvd

+0

Eso es exactamente lo que necesito, excepto Player.IsProfessional debe ser de solo lectura. Todas las alternativas que pude encontrar no son realmente agradables. –

Respuesta

8

Esto no se puede hacer con EF.Hay algunas opciones que no hacen exactamente lo que quiere, pero de acercarse más o menos:

  1. Crear una propiedad TeamPlayers en su contexto que devuelve los jugadores con el equipo incluido, por lo que siempre se puede hacer player.Team.IsProfessional incluso cuando el contexto ya se ha eliminado.

    public IQueryable<PLayer> TeamPlayers 
    { 
        get { return this.Players.Include("Team"); } 
    } 
    
  2. Crear un campo calculado en la tabla de base de datos y mapa para con DatabaseGeneratedOption.Computed.

  3. crear una propiedad estática en Player que devuelve la expresión que tiene acceso a Team.IsProfessional (requiere un contexto vivo o equipo incluido):

    public static Expression<Func<PLayer, bool>> IsProfessional 
    { 
        get { return p => p.Team.IsProfessional; } 
    } 
    ... 
    db.Players.Where(p=> p.FirstName="Lionel").Where(Player.IsProfessional).... 
    

yo preferiría el campo calculado, porque siempre es poblada , para que pueda usarlo dentro y fuera del alcance de un contexto.

+0

¡Genial! El campo calculado se ajusta mejor a mis necesidades: 1) Puedo consultar en el campo calculado, 2) está poblado con otras propiedades del Reproductor. ¡Muchas gracias! –

0

¿Qué sucede si extiende Player para tener una propiedad que se extrae del equipo?

public partial class Player 
{ 
    public int Id{get;set;} 
    public int TeamId{get;set;} 
    public string FirstName{get; set;} 
    public string LastName{get; set;} 
    public Team Team{get;set;} 

    public bool IsProfessional{ get { return Team.IsProfessional; } } 
} 

Por supuesto, si usted está preocupado acerca de la regeneración de su EDMX, puede que sea un parcial:

public partial class Player 
{ 
    public bool IsProfessional{ get { return Team.IsProfessional; } } 
} 
+0

Sí, pero de esta forma Player.IsProfessional no se puede utilizar en consultas de linq (como expliqué en la pregunta). Además, cuando se accede a la propiedad Player.IsProfessional, se realizará la consulta sql solo para obtener un booleano de db. Preferiría que ese booleano se complete al mismo tiempo que todas las demás propiedades del reproductor. –

0

Puede utilizar System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute para evitar el mapeo de la propiedad IsProfessional como estos:

// Mapped part of entity 
public class Player 
{ 
    public int Id { get; set; } 
    public int TeamId { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public Team Team { get; set; } 
} 

// Unmapped part of entity 
using System.ComponentModel.DataAnnotations.Schema; 
... 
public partial class Player 
{ 
    [NotMapped()] 
    public bool IsProfessional { get { /* ... IsProfessional calculation logic comes here ... */ } } 
} 

utilicé este atributo en el enfoque EF5's Model First y me preguntó sobre DbContext/DbSet y ObjectContext/ObjectQuery sin excepciones. (100% probado)

+0

OK, pero esta propiedad no aparece en el DataSource que creo desde esta entidad. –

+0

Normalmente uso ObjectDataSource y muestra todas las propiedades públicas de mis clases de entidad. Creo que EntityDataSource acaba de leer las propiedades mapeadas de las entidades generadas debido a su declaración de esquema en el archivo .edmx. – Perseus

+0

¿Funciona? ¿Qué pasa con los problemas de Linq se ha señalado anteriormente – Worthy7

Cuestiones relacionadas