从一种方法重用基础Linq查询

时间:2018-12-21 20:32:47

标签: c# .net linq

我正在尝试在整个项目中删除重复的代码,但我一直处于停滞状态,试图找出答案。我正在尝试做的是创建一个基本的linq查询,该查询将被重用于以多种不同的方法添加诸如Where,Take ...等内容。

const allData = _.range(0, 10, 0.001).map(x => ({
    x: x,
    y: Math.sin(Math.PI*x/2) * x / 10
}));

class CustomChart extends React.Component {
    constructor(props) {
        super();
        this.entireDomain = this.getEntireDomain(props);
        this.state = {
            zoomedXDomain: this.entireDomain.x,
        };
    }
    onDomainChange(domain) {
        this.setState({
            zoomedXDomain: domain.x,
        });
    }
    getData() {
        const { zoomedXDomain } = this.state;
        const { data, maxPoints } = this.props;
        const filtered = data.filter(
            (d) => (d.x >= zoomedXDomain[0] && d.x <= zoomedXDomain[1]));

        if (filtered.length > maxPoints ) {
            const k = Math.ceil(filtered.length / maxPoints);
            return filtered.filter(
                (d, i) => ((i % k) === 0)
            );
        }
        return filtered;
    }
    getEntireDomain(props) {
        const { data } = props;
        return {
            y: [_.minBy(data, d => d.y).y, _.maxBy(data, d => d.y).y],
            x: [ data[0].x, _.last(data).x ]
        };
    }
    getZoomFactor() {
        const { zoomedXDomain } = this.state;
        const factor = 10 / (zoomedXDomain[1] - zoomedXDomain[0]);
        return _.round(factor, factor < 3 ? 1 : 0);
    }
    render() {
        const renderedData = this.getData();
        return (
            <div>

                <VictoryChart
                    domain={this.entireDomain}
                    containerComponent={<VictoryZoomContainer
                        zoomDimension="x"
                        zoomDomain={this.state.zoomedXDomain}
                        onZoomDomainChange={this.onDomainChange.bind(this)}
                        minimumZoom={{x: 1/10000}}
                    />}
                >
                    <VictoryScatter data={renderedData} />
                </VictoryChart>

                <VictoryChart
                    domain={this.entireDomain}
                    containerComponent={<VictoryZoomContainer
                        zoomDimension="x"
                        zoomDomain={this.state.zoomedXDomain}
                        onZoomDomainChange={this.onDomainChange.bind(this)}
                        minimumZoom={{x: 1/10000}}
                    />}
                >
                    <VictoryScatter data={renderedData} />
                </VictoryChart>

                <div>
                    {this.getZoomFactor()}x zoom;
                    rendering {renderedData.length} of {this.props.data.length}
                </div>
            </div>
        );
    }
}

ReactDOM.render(<CustomChart data={allData} maxPoints={120} />, mountNode);

所以这将通过上面的基本查询进行,我将有一个单独的方法来重用VioLinq,但是这次将在其中使用where子句。

public IQueryable<Object> FooLinq(int id)
{
    using (var ctx = new dbEntities())
    {
        var results =
            (from account in ctx.account
                join memberProducts in ctx.tblMemberProducts on account.Id equals memberProducts.AccountId                 
                orderby account.date descending
                select new{account,memberProducts}).ToList();
        return results;
    }
}

3 个答案:

答案 0 :(得分:1)

您需要做两件事:

  1. 在具体化之前返回查询。
  2. 确保最终查询实现时上下文仍在范围内。

这两个要求会互相抵消,可以采用多种方法来满足它们。

例如,您可以使您的方法将上下文作为参数,从而迫使调用者提供它并管理其生命周期。

public IQueryable<AccountInfo> FooLinq(DbEntities ctx, int id)
{
        return
                from account in ctx.account                        
                orderby account.date descending
                select new AccountInfo()
                {
                    Name = account.Name,
                    Mid = account.MemberID,
                    Date = account.Date,
                    Address = account.Address,

                };
}

public List<IncomingViolations> Foo1(int id)
{
    using(var ctx = new dbEntities())
    {
        //Linq query FooLinq() where Name == "Bob"
        return FooLinq(ctx).Where(v => v.Name == "Bob").ToList();
    }
}

您也可以将上下文作为构造函数注入的依赖项注入,并使用DI框架来管理上下文的生命周期。

答案 1 :(得分:0)

您可以将其作为Queryable进行添加,然后为其添加条件。 例如:

public List<account> GetAccountsByName(string name, bool usePaging, int offset = 0, int take = 0) {
   var query = GetMyQuery();
   query = query.Where(x => x.Name == name);
   query = query.OrderBy(x => x.Name);
   if(usePaging) {
      query = query.Take(take).Skip(offset);
   }
   query = PrepareSelectForAccount(query);
   return query.ToList();    .
}

public IQueryable<account> GetMyQuery(){
 return ctx.account.AsQueryable();
}
public IQueryable<account> PrepareSelectForAccount(IQueryAble<account> query){
     return query.Select(select new AccountInfo()
                {
                    Name = account.Name,
                    Mid = account.MemberID,
                    Date = account.Date,
                    Address = account.Address,

                }
      );
}

答案 2 :(得分:-1)

可以,但是不要调用>=4,而是返回.ToList()而不是IQueryable<T>。 LINQ基于deferred execution的概念,这意味着直到对可枚举进行迭代之前,查询才真正执行。在此之前,您所要做的只是建立一个对象,该对象知道在时间到了时如何进行查询。

通过从设置“基本查询”的函数返回List<T>,然后可以随意使用其他LINQ方法(例如IQueryable<T>.Where())来生成修改后的查询。至此,您仍在简单地设置查询。实际上,只有在您遍历可枚举或调用类似.Take()之类的操作时,它才会执行。