Как я могу условно предотвратить обновление столбца в SQLite?
У меня есть таблица со столбцами CREATED и MODIFIED. Я только хочу вставить значение CREATED один раз и сделать его неизменным. Я знаю, как это сделать утомительно (напишите метод DoesRecordExist(), а затем измените запрос и количество параметров запроса на основе этого), но, безусловно, есть более простой способ сделать это. В конце концов, это должно быть общим требованием ("шаблон базы данных", если хотите).
Мой код такой:
public void InsertUserSiteRecord(UserSite us)
{
using (SQLiteConnection conn = new SQLiteConnection(HHSUtils.GetDBConnection()))
{
conn.Open();
using (SQLiteCommand cmd = new SQLiteCommand(conn))
{
cmd.CommandText =
String.Format(
@"INSERT INTO UserSite (SiteNum, SerialNum, UserName, Created, Modified)
VALUES (@SiteNum, @SerialNum, @UserName, @Created, @Modified)");
cmd.Parameters.Add(new SQLiteParameter("SiteNum", us.SiteNum));
cmd.Parameters.Add(new SQLiteParameter("SerialNum", us.SerialNum));
cmd.Parameters.Add(new SQLiteParameter("UserName", us.UserName));
cmd.Parameters.Add(new SQLiteParameter("Created", us.Created));
cmd.Parameters.Add(new SQLiteParameter("Modified", us.Modified));
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
... и я хочу избежать необходимости делать что-то вроде этого:
public void InsertUserSiteRecord(UserSite us)
{
using (SQLiteConnection conn = new SQLiteConnection(HHSUtils.GetDBConnection()))
{
conn.Open();
using (SQLiteCommand cmd = new SQLiteCommand(conn))
{
if (!RecordExists(us.SiteNum, us.SerialNum, us.UserName))
{
cmd.CommandText =
String.Format(
@"INSERT INTO UserSite (SiteNum, SerialNum, UserName, Created, Modified)
VALUES (@SiteNum, @SerialNum, @UserName, @Created, @Modified)");
else
{
cmd.CommandText =
String.Format(
@"INSERT INTO UserSite (SiteNum, SerialNum, UserName, Modified)
VALUES (@SiteNum, @SerialNum, @UserName, @Modified)");
}
cmd.Parameters.Add(new SQLiteParameter("SiteNum", us.SiteNum));
cmd.Parameters.Add(new SQLiteParameter("SerialNum", us.SerialNum));
cmd.Parameters.Add(new SQLiteParameter("UserName", us.UserName));
if (!RecordExists(us.SiteNum, us.SerialNum, us.UserName))
{
cmd.Parameters.Add(new SQLiteParameter("Created", us.Created));
}
cmd.Parameters.Add(new SQLiteParameter("Modified", us.Modified));
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
private bool RecordExists(String SiteNum, String SerialNum, String UserId)
{
// query the table to see if those three values exist in any record
}
Существует ли конструкция SQL[ite], которая выглядит примерно так:
cmd.Parameters.AddOnlyIfColumnIsEmpty(new SQLiteParameter("Created", us.Created));
? Или как это лучше всего решить?
ОБНОВИТЬ
Ответ Даба Стили гениален, но я, будучи мной, спустился по утомительному, но более легкому в грохоте камино и создал эти три метода:
public int UserSiteIdFor(String userName, String serialNum, String siteNum)
{
int Id;
const string qry = "SELECT Id FROM UserSite WHERE UserName =
@UserName AND SiteNum = @SiteNum AND SerialNum = @SerialNum";
try
{
using (SQLiteConnection con = new
SQLiteConnection(HHSUtils.GetDBConnection()))
{
con.Open();
SQLiteCommand cmd = new SQLiteCommand(qry, con);
cmd.Parameters.Add(new SQLiteParameter("UserName",
userName));
cmd.Parameters.Add(new SQLiteParameter("SiteNum", siteNum));
cmd.Parameters.Add(new SQLiteParameter("SerialNum",
serialNum));
Id = Convert.ToInt32(cmd.ExecuteScalar());
}
}
catch (Exception ex)
{
String msgInnerExAndStackTrace = String.Format(
"{0}; Inner Ex: {1}; Stack Trace: {2}", ex.Message,
ex.InnerException, ex.StackTrace);
ExceptionLoggingService.Instance.WriteLog(String.Format("From
TestHHSDBUtils.UserSiteIdFor: {0}", msgInnerExAndStackTrace));
return 0;
}
return Id;
}
public void InsertUserSiteRecord(UserSite us)
{
using (SQLiteConnection conn = new
SQLiteConnection(HHSUtils.GetDBConnection()))
{
conn.Open();
using (SQLiteCommand cmd = new SQLiteCommand(conn))
{
cmd.CommandText =
String.Format(
@"INSERT INTO UserSite (SiteNum, SerialNum,
UserName, Created, Modified)
VALUES (@SiteNum, @SerialNum, @UserName,
@Created, @Modified)");
cmd.Parameters.Add(new SQLiteParameter("SiteNum",
us.SiteNum));
cmd.Parameters.Add(new SQLiteParameter("SerialNum",
us.SerialNum));
cmd.Parameters.Add(new SQLiteParameter("UserName",
us.UserName));
cmd.Parameters.Add(new SQLiteParameter("Created",
us.Created));
cmd.Parameters.Add(new SQLiteParameter("Modified",
us.Modified));
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
public void UpdateUserSiteRecord(int Id, String lastLogin)
{
using (SQLiteConnection conn = new
SQLiteConnection(HHSUtils.GetDBConnection()))
{
conn.Open();
using (SQLiteCommand cmd = new SQLiteCommand(conn))
{
cmd.CommandText = String.Format(@"UPDATE UserSite SET
Modified = @Modified WHERE Id = @Id");
cmd.Parameters.Add(new SQLiteParameter("Id", Id));
cmd.Parameters.Add(new SQLiteParameter("Modified",
lastLogin));
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
... и называть их так:
int userSiteId = hhsdbutils.UserSiteIdFor(us.UserName, us.SerialNum, us.SiteNum);
if (userSiteId > 0)
{
hhsdbutils.UpdateUserSiteRecord(userSiteId, us.Modified);
}
else
{
hhsdbutils.InsertUserSiteRecord(us);
}
Оно работает.
2 ответа
Вам необходимо проверить наличие записи; затем выполните ОБНОВЛЕНИЕ, если оно существует (не изменяя созданное вами значение), и ВСТАВКУ, если это не так.
Ваш исходный код выдаст ошибку дублированного ключа, при условии, что у вас есть PK на столе.
Вы можете сделать это с помощью trigger
, См. Документацию SQLite по триггерам здесь: https://www.sqlite.org/lang_createtrigger.html
По сути, вы бы создали INSTEAD OF
триггер, затем настройте свой запрос соответственно. Из документации:
For an example of an INSTEAD OF trigger, consider the following schema:
CREATE TABLE customer(
cust_id INTEGER PRIMARY KEY,
cust_name TEXT,
cust_addr TEXT
);
CREATE VIEW customer_address AS
SELECT cust_id, cust_addr FROM customer;
CREATE TRIGGER cust_addr_chng
INSTEAD OF UPDATE OF cust_addr ON customer_address
BEGIN
UPDATE customer SET cust_addr=NEW.cust_addr
WHERE cust_id=NEW.cust_id;
END;
With the schema above, a statement of the form:
UPDATE customer_address SET cust_addr=$new_address WHERE cust_id=$cust_id;
Causes the customer.cust_addr field to be updated for a specific customer entry that has customer.cust_id equal to the $cust_id parameter. Note how the values assigned to the view are made available as field in the special "NEW" table within the trigger body.
Что вы хотели бы сделать, это просто настроить триггер, чтобы не обновлять этот столбец, даже если исходный запрос проходит в этом столбце для обновления.