我对linq很陌生,正在尝试弄清楚如何完成以下操作:
目前,我有一个Winforms项目,该项目有一个基本窗体,其中DataRow是其成员之一。 我有几个派生的表单根据数据表(SQL查询结果)中的数据填充数据行。 派生窗体上也有控件,这些控件也填充了数据中的值。 单击派生窗体上的"保存"按钮时,将更新基本窗体中的数据行,然后派生窗体通过 DataAdapter 更新数据库。
我想使用 linqs 替换所有 SQL 命令,因此我尝试通过以下方式使用 LINQ 实现此功能:
我在派生窗体中创建了 Linq 查询,并将结果分配给基本窗体中的对象。 我将基窗体中的对象强制转换为 Linq 查询的类类型,并使用反射填充派生窗体上的所有控件。 单击保存按钮时,我更新了对象,但无法更新数据库。
我无法解决的问题是对象更新后如何更新数据库。 此时,我没有用于 linq 查询的数据上下文。
我在 linq 查询中使用 SQL 函数,因此我不得不为这些值创建一个单独的类,因为我收到匿名类型错误。 我可能在这里错过了一些东西。
任何帮助将不胜感激,因为我真的很干净 linq 代码。
编辑(从布拉德的编辑复制到托马斯的答案):
以下是我的代码的 3 个步骤。
步骤 1 - 从数据库中获取数据的单一记录
private void GetDatabaseDetailData()
{
_db = new PriorityDataContext();
DetailData = (from db in _db.tblDatabases
where db.DatabaseID == Id
select db).SingleOrDefault();
DeveloperData = (from db in _db.tblDatabases
where db.DatabaseID == Id
select new DeveloperInfo
{
DeveloperName = _db.func_get_employee_name(db.Developer)
}).SingleOrDefault();
}
步骤 2 - 填充对象中存在名称的所有控件。 对象被强制转换为传递给此方法的特定类型。 为简洁起见,未显示所有代码。
protected virtual void PopulateDetailControlsA(List<Control> controlContainers, string srcDataTableName)
{
Object data = null;
Type type = null;
switch (srcDataTableName)
{
case "tblDatabases" :
type = typeof(tblDatabase);
data = (tblDatabase)DetailData;
break;
}
if (type != null)
{
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var controlContainer in controlContainers)
{
foreach (var propertyInfo in properties)
{
if (!ControlExists(controlContainer, propertyInfo.Name)) continue;
var txtControl = controlContainer.Controls[propertyInfo.Name] as ExtendedTextBox;
if (txtControl != null)
{
try
{
var value = propertyInfo.GetValue(data, null).ToString();
if (propertyInfo.Name == "row_oper_name" || propertyInfo.Name == "row_last_chng_oper_name")
{
txtControl.Text = RowOperatorData.RowOperatorName;
txtControl.ValueMember = propertyInfo.GetValue(data, null).ToString();
}
else
txtControl.Text = value;
}
catch (NullReferenceException)
{
}
continue;...........
步骤3 - 尝试将更改保存回派生发件人中的数据库。
private void SaveData()
{
try
{
_db.SubmitChanges();
}
catch (Exception sqlException)
{
}
}
我真正不清楚的是如何将结果集存储在基本窗体中,以便我可以对许多不同的查询使用相同的代码。 DataRow 运行良好,因为我将一些代码用于超过 25 个派生表单。
如果我理解正确,您可以在派生形式中创建DataContext
,然后使用它编写一些查询(以派生形式)。为了能够更新数据库,查询必须返回从表中获取的实体(即 select
子句应该只返回实体)。例如:
DataContext db = // ...
var q = from p in db.Things
where p.Some > 10 select p;
如果随后修改实体,则可以使用 db.SubmitChanges()
将更改(对实体对象所做的)存储到数据库。为此,您需要原始db
值。
在你的方案中,需要将DataContext
(作为字段)存储在派生窗体中。如果您需要从基本窗体执行更新,那么我建议您定义一个虚拟方法:
// Base form
protected abstract void UpdateDatabase();
// Derived from with field 'db' storing 'DataContext'
protected override void UpdateDatabase() {
db.SumbitChanges();
}