2012-10-09 16 views
6

Mam interesujący problem do rozwiązania, ale, choć często, wygląda na to, że nie jest łatwo osiągalny z Entity Framework. Dostępne są dwie tabele:Entity Framework - Właściwość tylko do odczytu obiektu odwzorowana na kolumnę pokrewnej tabeli

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

Gracz może należeć tylko do jednej drużyny. Korzystanie TPT (DB pierwszy), mamy dwie klasy odwzorowywane na tych tabelach:

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

Co chciałbym osiągnąć to własność IsProfessional na jednostkę gracza:

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 
    } 

Czy jest możliwe aby skonfigurować mapowanie że w jaki sposób właściwość IsProfessional może być używana w zapytaniach linq?

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

i aby to pole było wypełniane za każdym razem, gdy obiekt gracza się zmaterializował?

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

Już próbowałem z:

  • Entity Dzielenie. Nie jest możliwe, ponieważ chcę zachować mapowanie drużyn, a ponieważ relacja nie jest 1: 1)
  • Odwzorowanie podmiotu odtwarzacza na widok bazy danych. To się nie podobało, ponieważ istnieją inne relacje, których potrzebuje gracz. Wiem, że można je utworzyć ręcznie, ale aktualizacja edmx z bazy danych zresetuje ssdl.

Dzięki

Rozwiązanie

oparciu o drugiej opcji w Gert Arnold odpowiedź, rozwiązanie, które pasuje do moich potrzeb jest następujący:

  1. ja funkcję GetIsProfessional tworzyć (musiał zrób to, ponieważ pola obliczone zwykle mogą być wykonane tylko z własnych pól tabeli)

    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. stworzyłem pole obliczoną na Player tabeli

    ALTER TABLE Players ADD [IsProfessional] AS dbo.GetIsProfessional(TeamId) 
    
  3. Ponieważ używam db pierwsze podejście, po prostu zaktualizować model z bazą danych i to, czy mogę zapytać o tej dziedzinie i to pre zaludnione kiedy obiekt gracza się zmaterializuje.

+0

Więc 'Player.IsProfessional' powinien dać ten sam wynik co' Player.Team.IsProfessional'? EF nie obsługuje obecnie właściwości, które nie są mapowane do prostego pola bazy danych, przepraszam, ale być może ktoś odpowie dobrą alternatywą. – hvd

+0

Dokładnie tego potrzebuję, z wyjątkiem Player.IsProfessional powinien być tylko do odczytu. Wszystkie alternatywy, które mogłem znaleźć, nie są naprawdę ładne. –

Odpowiedz

8

ta nie może być wykonana z EF.Istnieje kilka opcji, które nie robią dokładnie to, co chcesz, ale się blisko bardziej lub mniej:

  1. Tworzenie właściwość TeamPlayers w swoim kontekście zwraca gracze z zespołu włączone, tak że zawsze można zrobić player.Team.IsProfessional, nawet jeśli kontekst został już dippedowany.

    public IQueryable<PLayer> TeamPlayers 
    { 
        get { return this.Players.Include("Team"); } 
    } 
    
  2. Utwórz pole obliczeniowe w tabeli bazy danych i map do niego z DatabaseGeneratedOption.Computed.

  3. Tworzenie właściwości statycznej w Player zwracającej ekspresję, która uzyskuje dostęp Team.IsProfessional (wymaga kontekst dzienną lub zespół w komplecie):

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

wolałbym pola obliczeniowego, ponieważ jest zawsze zaludnione , więc możesz go używać wewnątrz i poza zakresem kontekstu.

+0

Świetnie! Pole obliczone najlepiej odpowiada moim potrzebom: 1) Potrafię wyszukiwać w polu obliczonym, 2) jest wypełniane innymi właściwościami odtwarzacza. Wielkie dzięki! –

0

Co się stanie, jeśli przedłużysz Gracza, aby mieć własność, która ciągnie od zespołu?

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

Oczywiście, jeśli martwisz się o swoją EDMX regenerujące, można zrobić to częściowy:

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

Tak, ale w ten sposób Player.IsProfessional nie nadaje się do użycia w zapytaniach linq (jak to wyjaśniłem). Ponadto, gdy uzyskuje się dostęp do właściwości Player.IsProfessional, będzie wykonywał kwerendę sql, aby uzyskać tylko jedną wartość boolean z db. Wolałabym, gdyby ta wartość boolowska była wypełniona w tym samym czasie, co wszystkie inne właściwości odtwarzacza. –

0

Można użyć System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute aby zapobiec mapowanie właściwości IsProfessional takie jak:

// 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 ... */ } } 
} 

użyłem tego atrybutu w EF5's Model First podejścia i zapytaliśmy ponad DbContext/DbSet i ObjectContext/ObjectQuery bez żadnych wyjątków. (100% testowane)

+0

OK, ale ta właściwość nie jest wyświetlana w DataSource, które utworzę z tego obiektu. –

+0

Zazwyczaj używam ObjectDataSource i pokazuje wszystkie publiczne właściwości moich klas jednostek. Myślę, że EntityDataSource po prostu odczytuje zmapowane właściwości wygenerowanych jednostek z powodu ich deklaracji schematu w pliku .edmx. – Perseus

+0

Czy to działa? A co z problemami Linq opisanymi powyżej? – Worthy7