Используйте семафор (давайте назовем его StillNeedsValidating). если функция SaveForm видит, что семафор StillNeedsValidating произошел, имейте его, активируют второй собственный семафор (который я назову FormNeedsSaving здесь), и возврат. Когда проверка функционирует концы, если семафор FormNeedsSaving произошел, это вызывает функцию SaveForm самостоятельно.
В jankcode;
function UserInputChanged(control) {
StillNeedsValidating = true;
// do validation
StillNeedsValidating = false;
if (FormNeedsSaving) saveForm();
}
function SaveForm() {
if (StillNeedsValidating) { FormNeedsSaving=true; return; }
// call web service to save value
FormNeedsSaving = false;
}
Одна ошибка I см. повторение снова и снова:
Создание экземпляров и настройка всего (DbConnection, DbCommand, DbParameters) внутри метода, который вызывается многократно в замкнутом цикле.
В большинстве случаев вы можете выполнить рефакторинг этих локальных переменных как членов класса. создание их экземпляров только один раз и сохранение только обновлений DbParameters внутри метода.
ОБНОВЛЕНО, чтобы включить образец кода, запрошенный в комментариях
Отказ от ответственности: Это быстро собранный образец с единственной целью продемонстрировать суть удаления повторяющихся элементов из цикла. Другие лучшие практики не обязательно реализованы.
public static void Show() {
List people = new List();
//Everything is done inside the loop
PersonDal personDal = new PersonDal();
foreach (Person person in people) {
personDal.Insert(person);
}
//Things are setup once outside the loop.
using (DbConnection connection = SqlClientFactory.Instance.CreateConnection()) {
// setup the connection
BetterPersonDal betterPersonDal = new BetterPersonDal(connection);
connection.Open();
foreach (Person person in people) {
betterPersonDal.Insert(person);
}
}
}
}
class Person {
public int Id { get; set; }
public string Name { get; set; }
}
В этой первой реализации все настраивается каждый раз, когда вызывается метод:
class PersonDal {
public int Insert(Person person) {
DbProviderFactory factory = SqlClientFactory.Instance;
using (DbConnection connection = factory.CreateConnection()) {
connection.Open();
connection.ConnectionString = "Whatever";
using (DbCommand command = connection.CreateCommand()) {
command.CommandText = "Whatever";
command.CommandType = CommandType.StoredProcedure;
DbParameter id = command.CreateParameter();
id.ParameterName = "@Id";
id.DbType = DbType.Int32;
id.Value = person.Id;
DbParameter name = command.CreateParameter();
name.ParameterName = "@Name";
name.DbType = DbType.String;
name.Size = 50;
name.Value = person.Name;
command.Parameters.AddRange(new DbParameter[] { id, name });
return (int)command.ExecuteScalar();
}
}
}
}
Теперь мы перемещаем настройку в конструкцию объектов, оставляя ее вне цикла:
class BetterPersonDal {
private DbProviderFactory factory;
private DbConnection connection;
private DbCommand command;
private DbParameter id;
private DbParameter name;
public BetterPersonDal(DbConnection connection) {
this.command = connection.CreateCommand();
this.command.CommandText = "Whatever";
this.command.CommandType = CommandType.StoredProcedure;
this.id = command.CreateParameter();
this.id.ParameterName = "@Id";
this.id.DbType = DbType.Int32;
this.name = command.CreateParameter();
this.name.ParameterName = "@Name";
this.name.DbType = DbType.String;
this.name.Size = 50;
this.command.Parameters.AddRange(new DbParameter[] { id, name });
}
public int Insert(Person person) {
this.id.Value = person.Id;
this.name.Value = person.Name;
return (int)command.ExecuteScalar();
}
}
] Have a look at the Improving .NET Application Performance and Scalability book (available online for free, in MSDN). There's a whole chapter about improving ADO.NET performance.
Be very smart about connection management. Opening a DB connection can be very expensive so try and keep that in mind when writing the database access layer.
If you're not going to use an ORM, are you also not going to cache your data? That's a big advantage of using an ORM. If there's no data cache, you'll need to look at ways to cache the HTML/JavaScript. This can be accomplished using OutputCache directive and SqlDependency. Or by publishing out static HTML and JavaScript files. Either way, you will be able to handle higher load if you're not constantly hitting the database on every request.
Some links:
ASP.NET Web Site Performance Improvement http://www.codeproject.com/KB/aspnet/aspnetPerformance.aspx
10 ASP.NET Performance and Scalability Secrets http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx
Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx
The article Martin links to is excellent. I would just add that you definitely want to use a DataReader instead of a DataSet (I love DataSets, but not for performance reasons).