views:

474

answers:

3

Hi, i have a cost issue with datatable. And i need to replace the code with a smarter one.

i have a datatable and the sample values are like this:

Columns : id, user_id, starttime, endtime

Row Sample : 1 , 5, 05.10.2009 08:00:00,05.10.2009 17:00

my pseudo code is

    function something()
    {
    for(int i=0;i<datatable.Rows.Length;i++)
    {
    if(Someobject.variable.Equals(dt.Rows[i][user_id].ToString()))
    {
    if(Date.Compare(somevariable,dt.Rows[i][starttime].ToString())!=0)
    {
    //Do something
    }
    }
    }
}

it's something like that. The datatable has more than a thousand rows and the functions has to be called nearly a thousand times when the asp.net page loads.

So i have to change it.

i considered using dictionary but it seems that it takes only two variables. What can you suggest me.

Edit:

I could not solve the problem yet. Here is the related code. Thanks in advance.

protected void RadScheduler_Randevu_TimeSlotCreated(object sender, Telerik.Web.UI.TimeSlotCreatedEventArgs e) {

for (int i = 0; i < calismaSaatleridt.Rows.Count; i++)
{
    if (RadScheduler_Randevu.SelectedView.Equals(SchedulerViewType.DayView))
    {
        if (RadScheduler_Randevu.SelectedDate.ToShortDateString().Equals(Convert.ToDateTime(calismaSaatleridt.Rows[i]["calisma_baslangic"]).ToShortDateString()))
        {
            if (e.TimeSlot.Resource.Key.ToString().Equals(calismaSaatleridt.Rows[i]["hekim_id"].ToString()))
            {
                if (DateTime.Compare(e.TimeSlot.Start, Convert.ToDateTime(calismaSaatleridt.Rows[i]["calisma_baslangic"])) < 0 || DateTime.Compare(e.TimeSlot.End, Convert.ToDateTime(calismaSaatleridt.Rows[i]["calisma_bitis"])) > 0)
                {
                    e.TimeSlot.CssClass = "Disabled";
                }
            }
        }
    }
}

}

This is the function that returns the result set.

private DataTable calismaSaatiGetir(string yonetici_id)
    {
        SqlConnection connection = new SqlConnection();
        connection.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
        SqlCommand command = new SqlCommand();
        command.CommandText = "select calisma_saati.id,kullanici.id as hekim_id,LEFT(CONVERT(VARCHAR,calisma_saati.tarih,104),10)+ ' ' +LEFT(CONVERT(VARCHAR,calisma_saati.baslangic_saati,108),5) AS calisma_baslangic,LEFT(CONVERT(VARCHAR,calisma_saati.tarih,104),10)+ ' '+LEFT(CONVERT(VARCHAR,calisma_saati.bitis_saati,108),5) AS calisma_bitis from calisma_saati JOIN kullanici ON kullanici.id=calisma_saati.kullanici_id WHERE  yonetici_id='" +  Session["yonetici"].ToString() + "' ";
        command.Connection = connection;
        connection.Open();
        SqlDataAdapter da = new SqlDataAdapter(command.CommandText, connection);
        DataSet ds = new DataSet();
        da.Fill(ds, "calisma_saati");
        calismaSaatleridt = ds.Tables["calisma_saati"];
        connection.Close(); 
        return calismaSaatleridt;
    }
+2  A: 

Is this coming from a database directly? If so, why not just perform a query to get a more specific result set? Then you could use linq to get execute your function on each row.

More defined SQL: select * from table where userID = 'bob' and starttime between '1/1/2009 11:00 PM' and '1/1/2009 11:21 PM'

Linq:

DataTable table = getFromDb();
table.Rows.Cast<DataRow>().ToList().ForEach(x => RunMyFunction(x));

void RunMyFunction(DataRow row)
{

}
Climber104
yes the datatable is populated from the database query. Actually there are timeslots of an component and in the timeslot created event i need to check whether the user works between the start time and the end time so i disable the timeslots. I didn't know that i could do it with linq. Can you give me a sample.
Semih
Edited with sample
Climber104
+5  A: 

The datatable has more than a thousand rows and the functions has to be called nearly a thousand times

There's your problem. If I'm reading that right, you're looping through the entire datatable for every item in some other collection of data that isn't shown in the question.

The best way to fix this is at the database level: whatever you're doing to generate this datatable needs to know about your other data set so you can take it into account on the database (and make use of things like indexes and cached data). That might mean writing a select query that is much more complicated than what you're used to, but it's the right way to do this.

If this just isn't an option, you still want to re-work this in some way so that you only interate through everything once. If you're using c#, you can probably accomplish that via a linq query (or even just the IEnumerable extensions + lambda methods).

Regarding using a dictionary: it may take only two variables, but one of those variables could be a more-complicated object, like an entire datarow from your table. Either way, to give you anything like sample code we need a better idea of what that other data looks like and what your intended result is.

Joel Coehoorn
yes, i absolutely agree with you that looping is the real problem. The situation is like this: I have a radscheduler component it has a timeslotcreated event. On page load i need to check whether that time slot is enabled or disabled depending on the users. The event is called nearly a thousand times. So i can't change it. What i must do is to get as fast as i can from the datatable or something else. I can paste a sample code and sample data tomorrow but right now i don't have it. Thank you for the answer also.
Semih
In that case, you probably want to build a dictionary as soon as you get the datatable back, and keep it somewhere nice and public so that you don't have to keep going back to the db for it.
Joel Coehoorn
A: 

how about this? (it would be better if you could push this query to the database. but this will be faster than looping every row)

void something(DataTable dt, myobj Someobject, DateTime somevariable)
{
    string filterPattern = "user_id='{0}' AND starttime='{1}'";
    string filter = string.Format(filterPattern, 
                                  Someobject.variable, 
                                  somevariable);
    DataRow[] rows = dt.Select(filter);

    foreach (DataRow row in rows)
        DoSomething(row);
}
void DoSomething(DataRow row)
{
}
public class myobj
{
    public string variable { get; set; }
}
Matthew Whited
Thanks, I'll try that.
Semih