实体框架 - 实体只读属性映射到相关表的列

时间:2012-10-09 10:52:54

标签: entity-framework entity-framework-4 ef-database-first

我有一些有趣的问题需要解决,但是,虽然常见,但看起来它并不容易通过Entity Framework实现。有两个表:

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

玩家只能属于一个团队。使用TPT(DB优先),我们有两个映射到这些表的类:

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

我想要实现的是Player实体上的属性IsProfessional:

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
    }

是否可以配置映射,以便在linq查询中使用IsProfessional属性?

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

并且每次播放Player实体时都填充该字段?

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

已经尝试过:

  • 实体拆分。不可能,因为我想保持团队映射,因为关系不是1:1)
  • 将播放器实体映射到数据库视图。不喜欢它,因为玩家实体有我需要的其他关系。我知道可以手动创建它们,但是从数据库更新edmx将重置ssdl。

由于

解决方案

根据Gert Arnold的第二个选项回答,符合我需求的解决方案如下:

  1. 我创建了函数GetIsProfessional(必须这样做,因为计算字段通常只能从自己的表字段中创建)

    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. 我在Player

    上创建了计算字段
    ALTER TABLE Players ADD [IsProfessional] AS dbo.GetIsProfessional(TeamId)
    
  3. 由于我正在使用数据库第一种方法,我只是从数据库更新模型,就是这样,我可以在该字段上查询,并且在实现Player对象时预先填充它。

3 个答案:

答案 0 :(得分:8)

使用EF无法做到这一点。有些选项并不能完全符合您的要求,但可以或多或少地接近:

  1. 在您的上下文中创建一个属性TeamPlayers,返回包含该团队的玩家,这样即使已经使用了上下文,您也可以player.Team.IsProfessional

    public IQueryable<Player> TeamPlayers
    {
        get { return this.Players.Include("Team"); }
    }
    
  2. 在数据库表格中创建一个计算字段,并使用DatabaseGeneratedOption.Computed映射到该字段。

  3. Player中创建一个静态属性,返回访问Team.IsProfessional的表达式(需要包含生存环境或团队):

    public static Expression<Func<Player, bool>> IsProfessional
    {
        get { return p => p.Team.IsProfessional; }
    }
    ...
    db.Players.Where( p=> p.FirstName="Lionel").Where(Player.IsProfessional)....
    
  4. 我更喜欢计算字段,因为它总是被填充,因此您可以在上下文范围内外使用它。

答案 1 :(得分:0)

如果您将Player扩展为拥有从团队中获取的属性,该怎么办?

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

当然,如果您担心重新生成EDMX,可以将其变为部分:

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

答案 2 :(得分:0)

您可以使用System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute来阻止 IsProfessional 属性的映射,如下所示:

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

我在 EF5's Model First 方法中使用了此属性,并查询了 DbContext/DbSet ObjectContext/ObjectQuery ,没有任何例外。 (100%测试)

相关问题