将实体映射到DTO

时间:2017-08-27 18:39:52

标签: c# entity-framework

我有一个EF实体,我希望在使用流利语法时将其属性映射到带有函数的DTO。

以用户为例,我可以通过这种方式对其进行映射:

    public Task<List<JournalTransactionModel>> GetAllJournalRecords()
    {
        var journalRecords = db.JournalTransactions
            .Include(_ => _.JournalTransactionsAccounts)
            .Include(_ => _.User)
            .Select(_ => new JournalTransactionModel
            {
                JournalTransactionId = _.JournalTransactionId,
                Date = _.Date,
                Description = _.Description,
                User = new UserModel
                {
                    UserId = _.UserId,
                    FirstName = _.User.FirstName,
                    LastName = _.User.LastName,
                    FullName = _.User.FirstName + " " + _.User.LastName,
                    Email = _.User.Email,
                    UserName = _.User.UserName,
                    Password = _.User.Password,
                    UserRoleAndPermissions = new UserRoleModel
                    {
                        UserRoleId = _.User.UserRole.UserRoleId,
                        UserRoleName = _.User.UserRole.UserRoleName,
                        CanRead = _.User.UserRole.CanRead,
                        CanWrite = _.User.UserRole.CanWrite
                    }
                },
                TransactionAccounts = _.JournalTransactionsAccounts.Select(j => new JournalTransactionAccountModel
                {
                    JournalTransactionAccountId = j.Id,
                    JournalTransactionId = j.JournalTransactionId,
                    DebitAccount = j.DebitAccount != null ? new AccountModel
                    {
                        AccountId = j.DebitAccount.AccountId,
                        AccountCategoryName = j.DebitAccount.AccountCategory.AccountCategoryName,
                        AccountCategoryId = j.DebitAccount.AccountCategoryId,
                        AccountName = j.DebitAccount.AccountName,
                        IncreasesWhenDebited = j.DebitAccount.IncreasesWhenDebited
                    } : null,
                    CreditAccount = j.CreditAccount != null ? new AccountModel
                    {
                        AccountId = j.CreditAccount.AccountId,
                        AccountCategoryName = j.CreditAccount.AccountCategory.AccountCategoryName,
                        AccountCategoryId = j.CreditAccount.AccountCategoryId,
                        AccountName = j.CreditAccount.AccountName,
                        IncreasesWhenDebited = j.CreditAccount.IncreasesWhenDebited
                    } : null,
                    Amount = j.Amount,
                    Person = j.Person != null ? new PersonModel
                    {
                        PersonId = j.PersonId,
                        FirstName = j.Person.FirstName,
                        LastName = j.Person.LastName,
                        FullName = j.Person.FirstName + " " + j.Person.LastName,
                        Email = j.Person.Email,
                        SocialSecurityNumber = j.Person.SocialSecurityNumber,
                        PersonType = new PersonTypeModel
                        {
                            Id = j.Person.PeopleType.PeopleTypeId,
                            Name = j.Person.PeopleType.Name
                        }
                    } : null
                }).ToList()
            }).ToListAsync();
        return journalRecords;
    }

但是当我尝试创建一个返回UserModel的函数时,我一直得到异常

    public Task<List<JournalTransactionModel>> GetAllJournalRecords()
    {
        var journalRecords = db.JournalTransactions
            .Include(_ => _.JournalTransactionsAccounts)
            .Include(_ => _.User)
            .Select(_ => new JournalTransactionModel
            {
                JournalTransactionId = _.JournalTransactionId,
                Date = _.Date,
                Description = _.Description,
                User = MapUserToModel(_.User),
                TransactionAccounts = _.JournalTransactionsAccounts.Select(j => new JournalTransactionAccountModel
                {
                    JournalTransactionAccountId = j.Id,
                    JournalTransactionId = j.JournalTransactionId,
                    DebitAccount = j.DebitAccount != null ? new AccountModel
                    {
                        AccountId = j.DebitAccount.AccountId,
                        AccountCategoryName = j.DebitAccount.AccountCategory.AccountCategoryName,
                        AccountCategoryId = j.DebitAccount.AccountCategoryId,
                        AccountName = j.DebitAccount.AccountName,
                        IncreasesWhenDebited = j.DebitAccount.IncreasesWhenDebited
                    } : null,
                    CreditAccount = j.CreditAccount != null ? new AccountModel
                    {
                        AccountId = j.CreditAccount.AccountId,
                        AccountCategoryName = j.CreditAccount.AccountCategory.AccountCategoryName,
                        AccountCategoryId = j.CreditAccount.AccountCategoryId,
                        AccountName = j.CreditAccount.AccountName,
                        IncreasesWhenDebited = j.CreditAccount.IncreasesWhenDebited
                    } : null,
                    Amount = j.Amount,
                    Person = j.Person != null ? new PersonModel
                    {
                        PersonId = j.PersonId,
                        FirstName = j.Person.FirstName,
                        LastName = j.Person.LastName,
                        FullName = j.Person.FirstName + " " + j.Person.LastName,
                        Email = j.Person.Email,
                        SocialSecurityNumber = j.Person.SocialSecurityNumber,
                        PersonType = new PersonTypeModel
                        {
                            Id = j.Person.PeopleType.PeopleTypeId,
                            Name = j.Person.PeopleType.Name
                        }
                    } : null
                }).ToList()
            }).ToListAsync();
        return journalRecords;

那里出了什么问题?

这是我得到的消息:

  

“ExceptionMessage”:“LINQ to Entities无法识别方法'ACS.Hub.BusinessLogic.Models.UserModel MapUserToModel(ACS.Hub.Repository.User)'方法,并且此方法无法转换为商店表达式。 “

3 个答案:

答案 0 :(得分:1)

您无法在linq查询中调用自定义方法。原因是幕后LINQ将所有LINQ语句转换为有效的SQL语句。并且SQL语言当然没有名为MapUserToModel的函数的定义。一种解决方案是从您的MapUserToModel方法中取出代码并将其直接放在LINQ查询中。

<强> 编辑: 我们已经讨论了为什么你不能在我们想要在SQL服务器上执行的查询中使用自定义方法,我们还讨论过使用ToList()并在内存中进行映射并不是一件好事。但是,无论何时想要映射用户,您仍然面临着编写冗余代码的问题。由于我非常恼火地看到冗余代码,我花了一些时间来应对这种挑战,并找到了一个解决方案,它允许您只在一个地方编写映射代码并在任何需要的地方使用它。所以,让我们说我们保存在数据库中的原始用户实体称为User,我们的DTO类称为UserModel。这是代码:

public class UserModel
{
    public string Username { get; set; }
    public string Email { get; set; }
    public DateTime Birthday { get; set; }

    public DbUser DbUser
    {
        set
        {
            Username = value.UserName;
            Email = value.Email;
            Birthday = value.Birthday;
        }
    }
}

以下是我们如何使用它:

var journalRecords = db.JournalTransactions
.Include(_ => _.JournalTransactionsAccounts)
.Include(_ => _.User)
.Select(_ => new JournalTransactionModel
{
    JournalTransactionId = _.JournalTransactionId,
    Date = _.Date,
    Description = _.Description,
    User = new UserModel
    {
        DbUser = _
    }
    ...
});

我认为代码是自解释的,但简而言之,这里的技巧是在我们的DTO UserModel类中,我们为原始DbUser实体添加一个属性,我们只创建一个setter方法,从DbUser访问每个属性并分配它到自己的每个相应的属性。因此,如果您需要在将来添加或删除映射的某些属性,您只需转到此setter方法并在此处实现更改。

答案 1 :(得分:1)

在服务器LINQ查询中翻译的

IQueryable查询表达式。在您的情况下不受支持,因为您的子查询必须在内存上计算。 MapUserToModel方法想要使用计算数据。如果您想通过MapUserToModel方法填充用户属性,则可以在ToList()数据之前使用Select获取内存数据。

var journalRecords = db.JournalTransactions
            .Include(_ => _.JournalTransactionsAccounts)
            .Include(_ => _.User)
            .ToList()
            .Select(_ => new JournalTransactionModel
            {
              ....
            }

答案 2 :(得分:1)

您需要在调用toList()之前调用Select(),但这会严重降低查询的性能。这就是你得到错误的原因,因为Linq不知道如何将自定义方法转换为SQL,如Dejanin所说。但是,当您调用toList()方法时,将执行上一个查询,并且不再使用SQL完成操作。

相关问题