是否可以重用LINQ to Entities select语句的部分内容?

时间:2017-11-08 21:40:22

标签: c# entity-framework linq linq-to-sql linq-to-entities

使用LINQ to Entities时,有没有办法在其他选择的stements中重用选择语句的块?
例如,在下面的代码中,我使用LINQ从我的数据库中选择客户设备对象。我还从连接到客户设备表的表中选择一个相关的Model对象。

            list = context.PTT_CUSTOMER_DEVICES
                .Include(...)
                .Select(d => new CustomerDevice
                {
                    customerAssetTag = d.CustomerAssetTag,
                    customerDeviceID = d.CustomerDeviceID,
                    //This section is used in several LINQ statements throughout the application.
                    Model = new Model()
                    {
                        ModelID = d.PTS_MODELS.ModelID,
                        Name = d.PTS_MODELS.Name,
                        Make = new Make()
                        {
                            MakeID = d.PTS_MODELS.PTS_MAKES.MakeID,
                            Name = d.PTS_MODELS.PTS_MAKES.Name
                        }
                    }
                 })...

但是,数据库中还有其他对象也引用了Model表。在我对其他表的select语句中,我基本上将相同的Model = new Model()代码复制到那些不同表的select语句中。
我想知道的是,是否可以在多个选择中存储和重用该代码块?可能使用扩展方法?

4 个答案:

答案 0 :(得分:1)

作为Func<>的替代方案,您还可以使用扩展方法重用实体类型与其他POCO之间的转换。

public static IQueryable<CustomerDevice> ToCustomerDevice(this IQueryable<PTT_CUSTOMER_DEVICES> devices)
{
    return devices.Select(d => new CustomerDevice
    {
        customerAssetTag = d.CustomerAssetTag,
        customerDeviceID = d.CustomerDeviceID
    }
}

但是,EF不允许您嵌套这些,并且会抱怨它无法将嵌套扩展方法转换为SQL。

解决这个问题的方法是在内存中执行转换,而不是在SQL中执行转换:

public static Model ToModel(this PTS_MODELS model)
{
    return new Model()
    {
        ModelID = model.ModelID,
        Name = model.Name,
        Make = new Make()
        {
            MakeID = model.PTS_MAKES.MakeID,
            Name = model.PTS_MAKES.Name
        }
    };
}

public static IEnumerable<CustomerDevice> ToCustomerDevice(this IQueryable<PTT_CUSTOMER_DEVICES> devices)
{
    return devices
        .Include(d => d.PTS_MODELS.PTS_MAKES)
        .AsEnumerable() // Evaulate everything that follows in memory
        .Select(d => new CustomerDevice
        {
            customerAssetTag = d.CustomerAssetTag,
            customerDeviceID = d.CustomerDeviceID,
            Model = d.PTS_MODELS.ToModel()
        });
}

由于您现在返回IEnumerable<>任何进一步的Where()条件将在内存中而不是在SQL中进行评估,因此ToCustomerDevice()是您最后一次调用的重要性。

答案 1 :(得分:0)

如果这些表具有公共基类或实现相同的接口,则可以执行此操作。

为简单起见假设我有一个IQueryable<string> names。我可以这样排序:

IQueryable<string> sorted = names.OrderBy(name => name);

但如果我想稍后使用这种特殊类型,我可以这样做:

Func<IQueryable<string>, IQueryable<string>> orderBy = q => q.OrderBy(x => x);

现在打电话给我,我只是传递IQueryable<string>

IQueryable<string> sorted = orderBy(names);

答案 2 :(得分:0)

您需要为Model创建一个CustomerDevice的构造函数吗? (该实体适用于PTT_CUSTOMER_DEVICES

public Model(CustomerDevice d) {
    ModelID = d.PTS_MODELS.ModelID;
    Name = d.PTS_MODELS.Name;
    Make = new Make() {
        MakeID = d.PTS_MODELS.PTS_MAKES.MakeID,
        Name = d.PTS_MODELS.PTS_MAKES.Name
    };
}

然后你可以在LINQ中调用那个构造函数:

Model = new Model(d),

答案 3 :(得分:0)

您可以使用表达式:

public static Expression<Func<PTT_CUSTOMER_DEVICES, CustomerDevice>>
            CustomerDeviceExpression = d =>
                new CustomerDevice
                {
                    customerAssetTag = d.CustomerAssetTag,
                    customerDeviceID = d.CustomerDeviceID,

                    Model = new Model()
                    {
                        ModelID = d.PTS_MODELS.ModelID,
                        Name = d.PTS_MODELS.Name,
                        Make = new Make()
                        {
                            MakeID = d.PTS_MODELS.PTS_MAKES.MakeID,
                            Name = d.PTS_MODELS.PTS_MAKES.Name
                        }
                    }
                 };

然后:

list = context.PTT_CUSTOMER_DEVICES
            .Include(...)
            .Select(CustomerDeviceExpression)...