【问题标题】:How to Create a Run-Time Computed (NotMapped) Value in Entity Framework Code First如何首先在实体框架代码中创建运行时计算(未映射)值
【发布时间】:2011-05-28 13:47:51
【问题描述】:

我在 EF Code First 中有一个用户类,其中包含很多属性,每个用户都有一个“联系人”集合,这些“联系人”是作为总用户群的子集的其他用户。另一个集合“ContactOfOthers”正好相反,显示谁将此用户作为联系人,因为这是多对多关系。

public class User {

        [Key]
        public string UserName { get; set; }

        // Lots of other properties not relevant to this question...

        [NotMapped]
        public bool IsMyContact { get; set; }

        public virtual ICollection<User> Contacts { get; set; }
        public virtual ICollection<User> ContactOfOthers { get; set; }

}

我引入了一个名为 IsMyContact 的未映射(未映射到 DB)属性。这适用于用户查询一堆用户并且我需要在视图中显示哪些用户已经在他们的联系人列表中的情况。因此,如果用户是其“联系人”集合的一部分,则此属性应该为真。不应将其保存到数据库中,因为同一用户可能会有所不同,具体取决于执行查询的用户。

在上下文查询中是否有一种很好的方法可以做到这一点?它当然可以通过执行两个查询然后遍历主要查询来强制执行,寻找与用户联系人集合的匹配项,但我想知道是否有一种更优雅的方法可以从一个查询中执行此操作,投影运行-时间计算列到这个属性上?

【问题讨论】:

    标签: asp.net-mvc linq entity-framework linq-to-entities


    【解决方案1】:

    我不知道如何在查询中直接填充User 中的IsMyContact 属性。但是另一种方法可能是引入一个 ViewModel 包装 User 并且另外具有 IsMyContact 标志:

    public class UserViewModel
    {
        public bool IsMyContact { get; set; }
        public User User { get; set; }
    }
    

    User 类将不再具有 IsMyContact 标志。)

    然后,您可以在运行查询时投影到这种类型:

    string me = "That's me"; // name of the user who is selecting
    
    List<UserViewModel> list = context.Users
       .Where(u => ...some filter...)
       .Select(u => new UserViewModel
              {
                  IsMyContact = u.ContactOfOthers.Any(c => c.UserName == me),
                  User = u
              })
       .ToList();
    

    好处是:您只需要一次往返,并且不必加载整个Contacts 集合来确定IsMyContactFlag(但如果您愿意,也可以这样做)。

    缺点:您需要这种额外的 ViewModel 类型。

    【讨论】:

    • 效果很好,感谢您的建议。我所做的唯一更改是“我”必须在“ContactOfOthers”集合中,因为我使用它来表示有问题的用户是特定用途的联系人。
    【解决方案2】:

    可以这样做,但它远非“好方法”,因为您无法返回 User 类型的实例。您必须编写自定义 linq-to-entities 查询,并且必须解决两个问题:

    • 您不能投影到 linq-to-entities 中的映射类型
    • 您无法访问 linq-to-entities 中的非映射属性

    所以我关于这样做的未经测试的高级想法是:

    var query = from u in ctx.Users
                where u.Id != id // don't include current user - you can add other condition
                join c in ctx.Users
                             .Where(x => x.Id == id) // current user
                             .SelectMany(x => x.Contacts)
                    on u.Id equals c.Id into leftJoin
                from y in leftJoin.DefaultIfEmpty()
                select new 
                    {
                        UserName = u.UserName,
                        IsMyContact = y != null
                    };
    

    这应该是一个查询,它将加载成对的UserName 和用户是否联系的信息。如果您想要 User 实例,则必须执行以下操作:

    var users = query.AsEnumerable()
                     .Select(new User
                          {
                              // Project to list in linq-to-objects
                          });
    

    【讨论】:

    • 谢谢,它提供了关于查询要求的详细信息并回答了有关访问非映射类型的问题。将结合 Slauma 建议的视图模型概念对其进行测试。
    猜你喜欢
    • 2011-08-29
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多