[英]C# Sqlite 'constraint failed'
I have a BindingList which is the DataSource of a DataGridView. 我有一个BindingList,它是DataGridView的数据源。 I want to be able to use SqliteDataAdapter + SqliteCommandBuilder to simplify loading/saving to my Sqlite database, but because SqliteDataAdapter.Fill/Update both only take a DataTable or DataSet as a parameter, I am using extension methods to convert my BindingList to/from a DataTable.
我希望能够使用SqliteDataAdapter + SqliteCommandBuilder简化加载/保存到Sqlite数据库的操作,但是由于SqliteDataAdapter.Fill / Update都只将DataTable或DataSet作为参数,因此我正在使用扩展方法将BindingList往返于数据表。
When doing this, if I update some values in my BindingList, then try to update the DB, I am getting UNIQUE constraint failed exceptions. 这样做时,如果我更新BindingList中的某些值,然后尝试更新数据库,则会收到UNIQUE约束失败的异常。 I am not really sure why my SqliteDataAdapter is trying to execute INSERTs and not updates, considering no values have been added, only updated.
考虑到未添加任何值,仅更新了,我不确定我的SqliteDataAdapter为什么尝试执行INSERT而未更新。
I could DELETE * from the table
before calling adapter.Update, but that doesn't seem ideal or correct. 我可以在调用adapter.Update之前
DELETE * from the table
,但这似乎并不理想或不正确。
What is the proper way to achieve my goal (being able to use adapter.Fill/Update with a generic list)? 什么是实现我的目标的正确方法(能够使用adapter.Fill / Update并带有通用列表)?
public void LoadDatabase()
{
using (var conn = new SQLiteConnection(dbConnectionString))
{
using (var adapter = new SQLiteDataAdapter("SELECT * FROM proxies", conn))
{
var table = new DataTable();
adapter.Fill(table);
var list = new BindingList<Proxy>(table.ConvertTo<Proxy>());
foreach (var item in list)
{
proxies.Add(item);
}
}
}
}
public void SaveDatabase()
{
using (var conn = new SQLiteConnection(dbConnectionString))
{
using (var adapter = new SQLiteDataAdapter("SELECT * FROM proxies", conn))
{
using (var builder = new SQLiteCommandBuilder(adapter))
{
adapter.InsertCommand = builder.GetInsertCommand();
adapter.DeleteCommand = builder.GetDeleteCommand();
adapter.UpdateCommand = builder.GetUpdateCommand();
var table = proxies.ToDataTable();
adapter.Update(table);
}
}
}
}
Extension methods used: 使用的扩展方法:
public static List<T> ConvertTo<T>(this DataTable datatable) where T : new()
{
List<T> Temp = new List<T>();
try
{
List<string> columnsNames = new List<string>();
foreach (DataColumn DataColumn in datatable.Columns)
columnsNames.Add(DataColumn.ColumnName);
Temp = datatable.AsEnumerable().ToList().ConvertAll<T>(row => getObject<T>(row, columnsNames));
return Temp;
}
catch
{
return Temp;
}
}
public static T getObject<T>(DataRow row, List<string> columnsName) where T : new()
{
T obj = new T();
try
{
string columnname = "";
string value = "";
PropertyInfo[] Properties;
Properties = typeof(T).GetProperties();
foreach (PropertyInfo objProperty in Properties)
{
columnname = columnsName.Find(name => name.ToLower() == objProperty.Name.ToLower());
if (!string.IsNullOrEmpty(columnname))
{
value = row[columnname].ToString();
if (!string.IsNullOrEmpty(value))
{
if (objProperty.PropertyType.IsEnum)
{
objProperty.SetValue(obj, Enum.Parse(objProperty.PropertyType, value));
}
else
{
if (Nullable.GetUnderlyingType(objProperty.PropertyType) != null)
{
value = row[columnname].ToString().Replace("$", "").Replace(",", "");
objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(Nullable.GetUnderlyingType(objProperty.PropertyType).ToString())), null);
}
else
{
value = row[columnname].ToString().Replace("%", "");
objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(objProperty.PropertyType.ToString())), null);
}
}
}
}
}
return obj;
}
catch
{
return obj;
}
}
public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
I decided to just delete all records before executing adapter.Update(), it is the simplest solution I've been able to think of. 我决定在执行adapter.Update()之前删除所有记录,这是我想到的最简单的解决方案。 If anyone has a better idea, do tell.
如果有人有更好的主意,请告诉。
public void SaveDatabase()
{
using (var conn = new SQLiteConnection(dbConnectionString))
{
using (var adapter = new SQLiteDataAdapter("SELECT * FROM proxies", conn))
{
using (var builder = new SQLiteCommandBuilder(adapter))
{
conn.Open();
using (var cmd = new SQLiteCommand("DELETE FROM proxies", conn))
{
cmd.ExecuteNonQuery();
}
adapter.InsertCommand = builder.GetInsertCommand();
adapter.DeleteCommand = builder.GetDeleteCommand();
adapter.UpdateCommand = builder.GetUpdateCommand();
var table = proxies.ToDataTable();
adapter.Update(table);
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.