【问题标题】:Querying Entity Framework with an object使用对象查询实体框架
【发布时间】:2012-03-11 09:28:29
【问题描述】:

我是第一次尝试使用 Entity Framework,但有点卡住了。

我有一个 AccountDataAccess 类:

public class AccountDataAccess
{
    public IEnumerable<Account> Get(Account account)
    {

    }
}

还有另一个类,Account

public class Account
{
    string UserName { get; set; }
    string Password { get; set; }
    string Email { get; set; }
    Session Session { get; set; }
}

调用 AccountDataAccess.Get() 时,可以填充一个或多个帐户参数的字段(例如,只有 UserName 具有值)。 实体框架中是否有一种方法可以通过仅包含包含值的字段的搜索来查询数据库?

做了一些谷歌搜索后,我能看到的唯一方法是

    public IEnumerable<Account> Get(Account account)
    {
        StringBuilder queryStringBuilder = new StringBuilder("SELECT VALUE account FROM MyDatabase.Account as account WHERE ");
        if (!String.IsNullOrWhiteSpace(account.UserName))
            queryStringBuilder.Append("UserName = " + account.UserName);

        if (!String.IsNullOrWhiteSpace(account.Email))
            queryStringBuilder.Append("Email = " + account.Email);
        ...
        //continue for all fields
        //then call database
    }    

显然,这是一种糟糕的做法。有什么想法吗?

编辑

举个完整的例子,如果我有

Account account1 = new Account() {UserName = "UserA", Email = "UserA@email.com"};
Account account2 = new Account() {UserName = "UserB"};

我希望 account1 的查询是

    var _context = new EntityModel();

    return _context.Where(w => w.UserName == account.UserName
            && w.UserName == account1.UserName
            && w.Email == account1.Email
            ).ToList();

但是 account2 的查询忽略了电子邮件字段,因为它没有被填充:

    var _context = new EntityModel();

    return _context.Where(w => w.UserName == account2.UserName
            ).ToList();

所以我想我的问题是我可以动态生成 W​​here lambda 表达式以仅包含具有值的字段吗?

【问题讨论】:

  • 只是一个注释...在您的界面前加上一个 I... 是个好习惯,因此您应该将 Account 界面重命名为 IAccount。

标签: c# entity-framework


【解决方案1】:

在您添加像 ToList() 这样的评估操作之前,不会处理查询。因此,您可以做的一件事就是像在 SQL 中那样构建查询。

var query = _context.Accounts.AsQueryable();

if (!String.IsNullOrWhiteSpace(account1.UserName))
    query = query.Where(a => a.UserName == account1.UserName);

if (!String.IsNullOrWhiteSpace(account1.Email))
    query = query.Where(a => a.Email == account1.Email);

你也可以对查询语法做同样的事情,虽然它有点冗长。

当您完成构建查询后,在其上运行 ToList()、ToArray() 等以实际执行它并从数据库中读取。

【讨论】:

  • 希望有一种更通用的方法来做到这一点,但这对我来说是迄今为止最好的解决方案。干杯。
【解决方案2】:

简而言之,Entity Framework 的特点是将表映射到类(反之亦然)。也就是说,Account 类将在您的数据库中具有相应的表示形式,您应该通过查询上下文中包含的数据库集以强类型的方式访问它:

//Accounts is a dbset representing the db records for the Account table
_context.Accounts.Where(x => x.UserName == account.UserName && x.Password == account.Password && x.Email == account.Email);

这意味着只有在 EF 无法完成某些事情时才应该使用硬编码的 sql 语句(例如表参数)。现在的问题:)

与 ADO.Net 不同,当您使用 EF 进行查询时,您会返回一个或一个 POCO(Account 类)的列表,以及它的所有字段,无论它们是否有值。如果 Get(Account account) 中的参数是您的查询过滤器,那么您应该根据需要选择执行或不执行查询。 EF 基于强类型查询,如果你想要更动态的东西,你可以look to anonymous types 但请记住,使用内联语句应该是最后一张牌。 An overview of Entity Framework

【讨论】:

    【解决方案3】:

    您需要创建实体模型并在项目中使用实体模型并使用 LINQ 查询从数据库中提取内容,例如:

    using (var _context = new EntityModel()) {
     var value = from c in _ontext
                 select person 
    }
    

    您需要在创建实体模型后使用 Linq。实体会将该 LINQ 转换为 SQL 并执行代码。

    【讨论】:

    • 谢谢,但有没有办法将 where 子句添加到 linq 表达式中,它只查看填充在我的帐户对象中的字段?
    【解决方案4】:

    我不知道我是否理解您的问题,但是在实体框架对象中使用 WHERE 的查询将是这样的:

    public class AccountDataAccess
    {
        public IEnumerable<Account> Get(Account account)
        {
            var _context = new EntityModel();
    
            return _context.Where(w => w.UserName == account.UserName
                    && w.Password == account.Password
                    && w.Email == account.Email
                    /* && other you need */
                    ).ToList();
        }
    }
    

    此查询将返回IEnumerable&lt;Account&gt;,但此帐户不是您的帐户,而是实体框架的帐户。

    要退回您的帐户,您需要:

        public IEnumerable<Account> Get(Account account)
        {
            var _context = new List<Account>();
    
            return _context
                .Where(w => w.UserName == account.UserName
                    && w.Password == account.Password
                    && w.Email == account.Email
                )
                .Select(s => new Account {
                    UserName = s.UserName,
                    Password = s.Password,
                    Email = s.Email
                }).ToList();
        }
    

    但要使其工作,您需要将 Account 声明为类而不是接口。

    【讨论】:

    • 糟糕,已将 Account 更改为类。编辑了我的问题,希望更清楚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多