简体   繁体   English

保存的投影表达式,可以在具有两个源对象的不同linq表达式中重复使用

[英]Saved projection expression for re-use in different linq expressions with two source objects

This is how I would usually save a projection expression to re-use for my DTO's: 这通常是我保存投影表达式以重新用于DTO的方式:

public class MyUserDTO
{
    public string Forename { get; set; }
    public string Surname { get; set; }

    public static Expression<Func<MyUserDTO, MyUserDBObject>> FromDBUserProjection = u => new MyUserDTO() { Forename = u.Forename, Surname = u.Surname };

    public static IQueryable<MyUserDTO> FromDBUser(IQueryable<MyUserDBObject> dbRecords)
    {
        return dbRecords.Select(FromDBUserProjection);
    }
}

This is a simple DTO with the projection expression necessary to project from a particular database object. 这是一个简单的DTO,具有从特定数据库对象进行投影所必需的投影表达式。

Whenever I want to query this data from the database, I can use it like this so that I dont have to write the projection every time: 每当我想从数据库查询此数据时,都可以像这样使用它,这样我就不必每次都编写投影:

IQueryable<MyUserDTO> myUsers = MyUserDTO.FromDBUser(context.MyUserDBObjects.Where(u => u.Forename = "Bob"));

In this way I separate data mapping from my database queries and ensures that mapping is consistent across different queries. 通过这种方式,我将数据映射与数据库查询分开,并确保在不同查询之间的映射是一致的。 This usually works fine for me, but I now have a situation where I need to project from two different database objects eg something like this: 这通常对我来说很好,但是现在我需要从两个不同的数据库对象进行投影,例如:

public class MyCompositeDTO
{
    public string User1Forename { get; set; }
    public string User1Surname { get; set; }
    public string User2Forename { get; set; }
    public string User2Surname { get; set; }
}

//simplified example to demonstrate my question
IQueryable<MyCompositeDTO> matchingUsers = from u1 in context.MyUserDBObjects
                                           join u2 in context.MyUserDBObjects on u1.Surname equals u2.Surname
                                           select new MyCompositeDTO()
                                           {
                                               User1Forename = u1.Forename,
                                               User1Surname = u1.Surname,
                                               User2Forename = u2.Forename,
                                               User2Surname = u2.Surname
                                           };

In the above example I can easily create the projection within the original linq query as I have both u1 and u2 available at that point. 在上面的示例中,我可以轻松地在原始linq查询中创建投影,因为此时我同时拥有u1和u2。 But is there some way I can separate the projection into a different function as I have done in the first example and keep it as an IQueryable? 但是,是否可以像我在第一个示例中所做的那样,通过某种方式将投影分为不同的函数,并将其保留为IQueryable? There isn't a foreign key linking the two source records. 没有链接两个源记录的外键。

I am not as familiar with the query syntax so I will have to use the method syntax. 我对查询语法不太熟悉,因此必须使用方法语法。 In fact, I am not sure this can even be done with the query syntax; 实际上,我不确定甚至可以使用查询语法来完成; maybe somebody else can say for sure. 也许其他人可以肯定地说。

Given this expression: 给定此表达式:

public static readonly Expression<Func<MyUserDBObjects, MyUserDBObjects, MyCompositeDTO>> CompositeDtoProject = 
    (u1, u2) => 
        new MyCompositeDTO()
        {
            User1Forename = u1.Forename,
            User1Surname = u1.Surname,
            User2Forename = u2.Forename,
            User2Surname = u2.Surname
        };

You could do this: 您可以这样做:

IQueryable<MyCompositeDTO> matchingUsers =
    MyUserDBObjects
    .Join(
        MyUserDBObjects, 
        u1 => u1.Surname, 
        u2 => u2.Surname, 
        CompositeDtoProject);

Opinion Below Here: 下面的意见:

I don't normally offer opinions or alternatives that people never asked for instead of answering the question because, well, I don't care for it when people do that to my questions. 我通常不提供人们从未要求的观点或替代方案,而是回答人们的问题,因为,好吧,当人们对我的问题回答时,我并不在乎。 But since I have offered a solution to the question that was asked maybe I can get away with offering my unsolicited opinion. 但是由于我已经为提出的问题提供了解决方案,也许我可以不提出自己的意见。 To me, what you have going on is confusing. 对我来说,您所做的令人困惑。 I think the same thing could be accomplished in a more straightforward way. 我认为可以通过更直接的方式完成同一件事。 Consider this: 考虑一下:

public class MyUserDTO
{
    public string Forename { get; set; }
    public string Surname { get; set; }
}

public static class MyUserDtoExtensions
{
    public static IQueryable<MyUserDTO> AsDto(this IQueryable<MyUserDBObject> source)
    {
        return 
            source
            .Select(x => new MyUserDTO()
                {
                    Forename = u.Forename,
                    Surname = u.Surname
                }
    }
}

Then instead of this 然后代替这个

IQueryable<MyUserDTO> myUsers = MyUserDTO.FromDBUser(context.MyUserDBObjects.Where(u => u.Forename = "Bob"));

You could write this: 您可以这样写:

IQueryable<MyUserDto> myUser =
    context
    .MyUserDBObjects
    .Where(u => u.Forename = "Bob")
    .AsDto();

Which reads easier. 读起来比较容易。 Separating the projection out into a separate extensions class will also allow you to add additional features more easily. 将投影分为单独的扩展类也将使您更轻松地添加其他功能。 For instance, if you find yourself searching on the forename often you could add another extension method like this: 例如,如果您发现自己经常搜索该名字,则可以添加另一个扩展方法,如下所示:

public static IQueryable<MyUserDto> WhereForenameIs(this IQueryable<MyUserDto> source, string name)
{
    return
        source
        .Where(u => u.Forename = name);
}

and then do this: 然后执行以下操作:

IQueryable<MyUserDto> myUser =
    context
    .MyUserDBObjects
    .AsDto()
    .WhereForenameIs("Bob");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM