开发者

Having difficulty with specific Future<T> query and collections with nHibernate.

开发者 https://www.devze.com 2023-03-24 04:01 出处:网络
For the sake of example, I am removing non-queried and non-essential data just to figure out how to do the initial query here.

For the sake of example, I am removing non-queried and non-essential data just to figure out how to do the initial query here.

I have a model structure like this.

class Path {
  Guid Id { get; protected set; }
  IList<Step> Steps { get; set; }
  void AddStep(Step entity) {
    // write up bidirectional association
  }
}
class Step {
  Guid Id { get; protected set; }
  Path Path { get; set; }
  // other data irreleveent
}

Now assuming 50000 steps, each with 5000 steps... I do realize I don't want to return all of them at once. But putting a limit on my query fetch isn't my real problem.

Here is the exact query I am attempting to use. I am getting the exception..

NHibernate.QueryException : duplicate alias: lpStep ----> System.ArgumentException : An item with the same key has already been added.

I'm not entirely sure how to handle this scenario. if I use a flat out Fetch on the Path query, I get Select+N errors from the NHibernate Profiler.

I do have batching enabled - but as far as I am aware, that only really applies to inserts, not retrievals. But in any case I am getting back these errors and not sure how to handle it. Any ideas?

using (var Transaction = Session.BeginTransaction()) {

                Path lpPath = null;
                Step lpStep = null;

                var lpPaths = Session.QueryOver<Path>(() => lpPath)
                    .Take(50)
                    .Future<Path>();

                var lpSteps = Session.QueryOver<Step>(() => lpStep)
                    .JoinAlias(() => lpPath.Steps, () => lpStep)
                    .Where(o => o.Path.Id == lpPath.Id)
                    .Take(12)
                    .Future<Step>();

                Transaction.Commit();

                foreach (var path in lpPaths) {
                  开发者_StackOverflow中文版  Console.WriteLine("{0} fetched {1} Steps",
                        path.Id, path.Steps.Count);
                }
            }

I basically want to say ..

Select (50) Paths, also, as a separate select but part of the same trip, Select the first (12) Steps that belong the previously selected Paths.

But if I use a flat out join, I get 110 rows, whereas I expect to have 2 tables, 1 of 50 rows, 1 of 600 rows.

Can someone explain to me what I am doing wrong?

mind you, I can do some minor alterations and the query runs, but it isn't 'optimized'. I can get the data I want, but it takes multiple trips and lazy loading. I can optimize the actual Path selection easily enough but it is those blasted Steps. If I just take a restrictive where clause out of the lpSteps query, it just returns the first 12 steps, not returning 12 steps for each query done.

I've looked at some of the other stack overflow posts on Future<T> and found them to look a lot like this. So I don't understand why it isn't working. I suspect that what is going on is this..

lpPaths runs.

lpSteps tries to run, first one succeeds.

lpSteps then tries to run again, finds it cannot redefine lpPaths.

Apocolypse

I'm really hoping someone smarter than me can enlighten me on the absolute most optimal way to write this.


i cant really understand what your use case is. why do you only need the first 12 Steps of each Path? What about batches of Steps to process

IList<Guid> pathIds;
while ((pathIds = QueryOver.For<Path>()
     .Where(...)
     .Projection(path => path.Id)
     .SetmaxResults(100)).Count > 0)
{

    int batch = 0;
    const int batchsize = 600;
    IList<Step> steps;
    while ((steps = Session.QueryOver<Step>()
        .Where(step => step.Path.Id).In(pathIds)
        .Where(step => step. ...)
        .SetFirstResult(batch * batchsize)
        .Take(batchsize)
        .List<Step>()).Count > 0)
    {
        DoSomething(steps);
        batch++;
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消