如何在实体框架中的部分类中包含非相关实体?

时间:2011-11-10 20:15:29

标签: c# entity-framework

我正在尝试将部分类中的属性添加到实体框架模型,该实体框架模型包括已通过导航属性与某些其他行联合映射的实体。

数据库: 我有一个带有UserID主键的Users表。另外,我有一个带有OwnerUserID(外键,可为空)的Tags表,如果它是用户特定的,则设置为UserID,但也可以为null,表示它适用于所有用户。

EF模型: 正确生成导航属性Users.Tags以包括显式分配给该用户的所有标记。

问题: 我需要User实体上的一个属性,该属性包含具有User 的OwnerUserID和为null的所有标记。 所以我希望能够说出这样的话:

public partial class User
    {
        public IEnumerable<Tag> VisibleTags
        {
            get
            {
                return tags = (from t in {AllTags}
                                where t.PrivateUserID == null
                                select t).Union(
                                from t in this.Tags
                                select t);
            }
        }
    }

...其中{AllTags}代表系统中的所有标签。

1 个答案:

答案 0 :(得分:3)

对设计的快速评论:

null提供上下文信息(例如适用于所有用户的值)时,我不是数据库中可空值的忠实粉丝,尤其是没有用户相反。

您可能需要考虑可以对用户进行分组的设计,并且标签对一组用户可见。如果您的需求在未来发生变化,并且更加明确,这将更加灵活。它也可以使你可以使列不可为空。

如果您现在不想将其构建到系统中,我会亲自策划从当前设计到基于组的设计的迁移是什么样的,只是为了确保您没有自己画画在设计方面进入角落。

手头的问题

您从上下文中获得AllTags,因此您将不得不使用上下文对象。

尝试1

执行此操作的一种方法是在上下文中创建一个接受UserUserId的方法。

// In partial Context class...

public IEnumerable<Tag> GetVisibleTags(User user)
{
    return Tags.Where(t => t.PrivateUserID == null)
        .Union(user.Tags)
        ;
}

// Call it like this...

context.GetVisibleTags(someUser);

我不完全喜欢,因为我不认为应该使用上下文来进行查询。这是“存储库”(实体/ DbSet / DataSet类)的工作。

尝试2

另一种方法(可以让用户访问它)是为getter方法添加一个context参数:

// In partial User class...

public IEnumerable<Tag> GetVisibleTags(MyContextClass context)
{
    return context.Tags.Where(t => t.PrivateUserID == null)
        .Union(this.Tags)
        ;
}

// Call it like this

someUser.GetVisibleTags(context);

我比第一个更喜欢这个,因为不应该允许“存储库”(entity / DataSet / DbSet)知道有关上下文的任何内容。

尝试3

您可以创建一个查询包装器对象来解决此问题。我建议你尽可能用这种方式编写复杂的查询,这样它们就可以重用了。

诀窍是找出一个好的域名特定名称...

// Todo: This is a terrible name.
// Figure out what makes more sense in your domain, by seeing where you use it
public class VisibleTags
{
    private readonly IMyContextClass context;

    public VisibleTags(IMyContextClass context)
    {
        this.context = context;
    }

    // Todo: Try to see if you can get this to return IQueryable.
    // I haven't used Union, so I'm not sure if it breaks that ability or not...
    public IEnumerable<Tag> GetVisibleTags(User user)
    {
        return context.Tags
            .Where(t => t.PrivateUserID == null)
            .Union(user.Tags)
            ;
    }
}