搜索单个结果时与Entity Framework一起使用的集合

时间:2013-05-23 19:49:56

标签: c# entity-framework collections

我按照实体框架教程编写了一个ApplicationConfig模型(这是简化的) -

public class ApplicationConfig
{
    public ApplicationConfig()
    {
        this.Users = new Collection<User>();
        this.Roles = new Collection<Role>();
    }

    public string Namespace { get; set; }
    public virtual ICollection<User> Users { get; set; }
    public virtual ICollection<Role> Roles { get; set; }
}


public class User
{
    public User()
    {
        this.Roles = new Collection<Role>();
        this.ApplicationConfigs = new Collection<ApplicationConfig>();
    }

    public int UserId { get; set; }

    public string Username { get; set; }
    public string Password { get; set; }

    public virtual ICollection<Role> Roles { get; set; }
    public virtual ICollection<ApplicationConfig> ApplicationConfigs { get; set; }
}

我有一种检查特定应用程序的用户名/密码的方法 -

public User ValidateUser(string applicationNamespace, string username, string password)
{
    var applicationConfig = GetApplicationConfig(applicationNamespace);

    User user = null;
    if (applicationConfig != null)
    {
       user = applicationConfig.Users.FirstOrDefault(u => u.Username.ToLower() == username && u.Password == password);
    }
    return user;
}

我可以为应用程序提供数百或数千个用户,但是对于此密码检查,我只希望返回匹配的用户。

ICollection和上面的查询是否可以用于此目的?

我主要担心的是applicationConfig.Users将填满所有数千名用户,即使我只想查询一个。

或者我应该使用IQueryable或IEnumerable还是其他什么?

2 个答案:

答案 0 :(得分:4)

不好看。您的问题是有效的,您必须使用IQueryable<User>,最终返回到您的实体框架DbSet<User>(或ObjectSet<User>)的DbContext(或ObjectContext)为了确保您在加载了数千个用户之后在数据库中实际查询用户而不是内存。

我完全不理解你的ApplicationConfig架构,但你必须在某处调用:

user = context.Users.FirstOrDefault(u =>
     u.Username.ToLower() == username && u.Password == password);

基本上是相同的LINQ,但context(=派生DbContext(或ObjectContext)的实例)而不是applicationConfig。这将被转换为过滤数据库中用户的SQL查询。

修改

如果ApplicationConfig类是模型和数据库中与UserRole有关系的实体,您仍然可以根据凭据 applicationNamespace由单个数据库查询,而无需为应用程序加载所有用户。它可能看起来像这样:

public User ValidateUser(string applicationNamespace,
    string username, string password)
{
    return context.ApplicationConfigs
        .Where(a => a.Namespace == applicationNamespace)
        .Select(a => a.Users
            .Where(u => u.Username.ToLower() == username &&
                u.Password == password)
            .FirstOrDefault())
        .FirstOrDefault();
}

或者 - 如果您向User实体提供ApplicationConfigs集合(根据您在下面的评论,我假设一个用户帐户可以参与许多应用程序 - &gt;多对付许多关系) - 您可以这样编写查询:

public User ValidateUser(string applicationNamespace,
    string username, string password)
{
    return context.Users
        .FirstOrDefault(u =>
            u.ApplicationConfigs.Any(a => a.Namespace == applicationNamespace) &&
            u.Username.ToLower() == username && u.Password == password);
}

我更喜欢后一版本,因为如果您需要,可以在Include(u => u.Roles)之后添加context.Users,轻松添加用户的角色。

在任何情况下,关键是让context可用于在一个步骤中执行完整验证。不要将其分为两部分,例如首先向所有用户加载ApplicationConfig,然后从加载的Users集合中归档用户。

答案 1 :(得分:0)

看起来不错。你可以简化回报:

public User ValidateUser(string applicationNamespace, string username, string password)
{
   var applicationConfig = GetApplicationConfig(applicationNamespace);

   if (applicationConfig != null)
   {
       return applicationConfig.Users.FirstOrDefault(u => u.Username.ToLower() == username && u.Password == password);
   }
   return null;
}