简体   繁体   English

中止ado.net查询

[英]Abort ado.net query

I am implementing a autocomplete control. 我正在实现自动完成控制。 Every time the user types a new character into a input, a query will fire. 每次用户在输入中输入新字符时,都会触发查询。 In order to test I have created a large database where the average query takes about 5 seconds to execute. 为了进行测试,我创建了一个大型数据库,平均查询执行时间约为5秒。

Because the query takes 5 seconds to execute I execute the query on a new thread: 因为查询需要5秒钟才能执行,所以我在新线程上执行查询:

   // execute the following lamda expression when user enters characters to textbox
   textBox1.TextChanged +=(x,eventArgs)=>{

            // execute query on separate thread
            new Thread(new ThreadStart(() =>
            {
                ObservableCollection = MyEntities.Entities.Products.Where(p => p.Name.Contains(inputText));
            })).Start();
    };

ObservableCollection and inputText are properties binded to my textbox and list. ObservableCollection和inputText是绑定到我的文本框和列表的属性。

The problem is that if the user types two characters my program will be running two threads at the same time. 问题是,如果用户键入两个字符,则我的程序将同时运行两个线程。 How can I abort the query? 如何终止查询?


Things that I am thinking about: 我正在考虑的事情:

Create a bool variable IsQueryRuning and set it equal to true quen query starts and equal to false when thread ends. 创建一个布尔变量IsQueryRuning并将其设置为等于真队列查询开始,并等于线程结束时为false。 If a new query will be executed and IsQueryRuning = true then I can set ObservableCollection =null and cause an exeption. 如果将执行一个新查询并且IsQueryRuning = true,那么我可以将ObservableCollection = null设置为异常。 I will then resove it with a try catch block. 然后,我将使用try catch块将其解决。 I think that technique is not the best approach.. 我认为该技术不是最佳方法。


Edit: 编辑:

Setting property Collection=null sometimes causes an exception and some other times it does not... 设置属性Collection = null有时会导致异常,而有时不会。

I would suggest a different approach, if that is possible to change for you. 如果可以为您带来改变,我建议您采用其他方法。

Instead of querying on each keystroke of the user, I would only do a query after, for example, 3 characters. 而不是查询用户的每次击键,我只会在例如3个字符之后进行查询。 Keep the result in some collection in memory. 将结果保存在内存中的某个集合中。

After that, only do the next queries on the in-memory collection. 之后,仅对内存集合进行下一个查询。 That spares you any following database accesses that are always much slower and ou should get a considerable performance gain. 这样可以避免您以后进行的任何数据库访问,这些访问总是慢得多,并且您应该获得可观的性能提升。

class Program
{        
    public class Person
    {
        public string Name;
        public int Age;
    }        

    public static void ExecuteQueryAsync ( IEnumerable<Person> collectionToQuery , Action<List<Person>> onQueryTerminated , out Action stopExecutionOfQuery )
    {
        var abort = false;

        stopExecutionOfQuery = () =>
        {
            abort = true;
        };            

        Task.Factory.StartNew( () =>
        {
            try
            {
                var query = collectionToQuery.Where( x =>
                {
                    if ( abort )
                        throw new NotImplementedException( "Query aborted" );

                    // query logic:
                    if ( x.Age < 25 )
                        return true;
                    return
                        false;
                } );

                onQueryTerminated( query.ToList() );

            }
            catch
            {
                onQueryTerminated( null );
            }
        });
    }


    static void Main ( string[] args )
    {
        Random random = new Random();

        Person[] people = new Person[ 1000000 ];

        // populate array
        for ( var i = 0 ; i < people.Length ; i++ )
            people[ i ] = new Person() { Age = random.Next( 0 , 100 ) };

        Action abortQuery;
        ExecuteQueryAsync( people , OnQueryDone , out abortQuery );

        // if after some time user wants to stop query:
        abortQuery();

        Console.Read();
    }

    static void OnQueryDone ( List<Person> results )
    {
        if ( results == null )
            Console.WriteLine( "Query was canceled by the user" );
        else
            Console.WriteLine( "Query yield " + results.Count + " results" );
    }
}

I had to execute the query like: 我必须像执行查询:

    public IEnumerable<T> ExecuteQuery(IEnumerable<T> query)
    {
        foreach (var t in query)
        {
            if (counterOfSymultaneosQueries > 1)
            {
                // if there are more than two queries break from the last one
                // breaking from it will decrease counterOfSymoltanosQueries
                break;
            }
            yield return t;
        }
    }

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

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