简体   繁体   English

删除行-多个表不支持生成的SQL

[英]Delete row - generated sql is not supported for multiple table

I am joining tables in my command. 我在命令中加入表格。 I would like to delete the current row. 我想删除当前行。
Below is my command and what I usually do. 以下是我的命令以及通常执行的操作。
But today I have the error: 但是今天我有错误:

generated sql is not supported for multiple table delete row 多表删除行不支持生成的sql

What does that mean?? 这意味着什么??

OleDbCommand mycmdL = new OleDbCommand("SELECT DISTINCT AreaSize.*, Bathrooms.*, Cities.*, Prices.*, Properties.*, Rooms.*, Types.*, Users.* FROM Users INNER JOIN (Types INNER JOIN (Rooms INNER JOIN (Prices INNER JOIN (Cities INNER JOIN (Bathrooms INNER JOIN (AreaSize INNER JOIN Properties ON AreaSize.AreaSizeID = Properties.AreaSize) ON Bathrooms.BathroomID = Properties.Bathrooms) ON Cities.CityID = Properties.City) ON Prices.PriceID = Properties.Price) ON Rooms.RoomID = Properties.Rooms) ON Types.TypeID = Properties.PropertyType) ON Users.UserID = Properties.AgentID WHERE Users.UserID =@userID", clsDataSource.mycon);

myadaptL = new OleDbDataAdapter(mycmdL);
myadaptL.Fill(clsDataSource.myset, "Properties");
tbListing = clsDataSource.myset.Tables["Properties"];

Code to delete current row: 删除当前行的代码:

try
        {
            if (MessageBox.Show("Are you sure?", "??", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                DataRow myrow = tbListing.Rows[current];
                myrow.Delete();
                OleDbCommandBuilder mybuild = new OleDbCommandBuilder(myadaptL);
                myadaptL.Update(tbListing);

            }
        }
        catch (Exception)
        {

            throw;
        }
    }

But today I have the error: 但是今天我有错误:
generated sql is not supported for multiple table delete row

What does that mean?? 这意味着什么??

As the error message says, the DbCommandBuilder can only auto-generate SQL for single table queries. 如错误消息所述, DbCommandBuilder只能为单表查询自动生成SQL。 This makes it easy to implement apps maintaining base tables such as Customer, Product, Employee etc. They can be used for something like a Customer-Order-OrderLines-ServiceItem relationship, but you have to go about it differently. 这样可以轻松实现维护基本表(例如客户,产品,员工等)的应用程序。它们可以用于诸如Customer-Order-OrderLines-ServiceItem关系之类的东西,但是您必须进行不同的处理。

But before you do that know that there are various frameworks out there to help implement and manage this kind of thing for you. 但是在您这样做之前,请先知道有各种框架可以帮助您实现和管理这种事情。 Look into ORMs. 查看ORM。


Since the DataAdapter can only update one table at a time, you will need multiple Adapters. 由于DataAdapter一次只能更新一个表,因此您将需要多个适配器。 Rather than using a SQL JOIN, you can define the PK-FK relationship. 您可以定义PK-FK关系,而不是使用SQL JOIN。 Changes to parent rows will cascade to children. 对父级行的更改将级联到子级。

For demo purposes I have tables cleverly names Parent , Child and SubChild . 出于演示目的,我巧妙地将表命名为ParentChildSubChild A parent row can have many child rows (1:m); 父行可以有许多子行(1:m); each child can have many subchild rows (1:m). 每个孩子可以有许多子孩子行(1:m)。

// form/class level objects
DataSet dsSample;
OleDbDataAdapter daParent;
OleDbDataAdapter daChild;
OleDbDataAdapter daSubCh;

Elsewhere, configure them: 在其他地方,配置它们:

daParent = new OleDbDataAdapter("SELECT Id, Name, Lorem FROM Parent",
    AceConnStr);
dsSample.Tables.Add("Parent");

var cbP = new OleDbCommandBuilder(daParent);
daParent.UpdateCommand = cbP.GetUpdateCommand();
daParent.InsertCommand = cbP.GetInsertCommand();
daParent.FillSchema(dsSample.Tables["Parent"], SchemaType.Source);
daParent.Fill(dsSample.Tables["Parent"]);


// repeat for Child - use care with copy-paste!
daChild = new OleDbDataAdapter("SELECT Id, ParentId, Name, Lorem FROM Child",
                AceConnStr);
dsSample.Tables.Add("Child");

var cbS = new OleDbCommandBuilder(daChild);
daChild.UpdateCommand = cbS.GetUpdateCommand();
daChild.InsertCommand = cbS.GetInsertCommand();
daChild.FillSchema(dsSample.Tables["Child"], SchemaType.Source);
daChild.Fill(dsSample.Tables["Child"]);

// do the same for the subchild adapter
// omitted for brevity
// ...

// the PK cols
DataColumn colParent = dsSample.Tables["Parent"].Columns["Id"];
DataColumn colChild = dsSample.Tables["Child"].Columns["Id"];


// set FK constraints, rules
ForeignKeyConstraint fkParentChild = new ForeignKeyConstraint("ParentChild",
            colParent, 
            dsSample.Tables["Child"].Columns["ParentId"]);
fkParentChild.DeleteRule = Rule.Cascade;
fkParentChild.UpdateRule = Rule.Cascade;
fkParentChild.AcceptRejectRule = AcceptRejectRule.Cascade;
dsSample.Tables["Child"].Constraints.Add(fkParentChild);


// set FK constraints, rules for Child-SubChild
ForeignKeyConstraint fkChildSub = new ForeignKeyConstraint("ChildSub",
             colChild, 
             dsSample.Tables["SubChild"].Columns["ChildId"]);
fkChildSub.DeleteRule = Rule.Cascade;
fkChildSub.UpdateRule = Rule.Cascade;
fkChildSub.AcceptRejectRule = AcceptRejectRule.Cascade;
dsSample.Tables["SubChild"].Constraints.Add(fkChildSub);

dsSample.EnforceConstraints = true;

When a Parent row is deleted the related child rows will be affected; 当父行被删除时,相关的子行将受到影响; same for Child-to-SubChild. 子对子子相同。 Note that even if you do not opt for some sort of ORM, lots of this can be broken up and handled by classes related to the actor. 请注意,即使您不选择某种ORM,也可以通过与actor相关的类来分解和处理其中的许多内容。 For instance, a Room or City class handling that bit of data. 例如,一个RoomCity类处理该数据位。

Testing the Relationship(s) 测试关系

A query for the rows related to "ParentB": 查询与“ ParentB”相关的行:

在此处输入图片说明

  • There are 3 related child rows (3 distinct Child.Ids) 有3个相关的子行(3个不同的Child.Ids)
  • There are 4 SubChild rows related to those ChildRows 有4个与那些ChildRows相关的SubChild行
  • If you care to decode the names, ChildB1 is the first child row for ParentB; 如果您想解码名称,则ChildB1ChildB1的第一子行; ChildB-1C means the subchild is related to the First childrow related to parentB. ChildB-1C表示子孩子与与parentB有关的第一个子行有关。 That didnt turn out as clear as I thought it would. 结果并没有我想的那么清楚。

Test: 测试:

// delete ParentB
var dr = dsSample.Tables["Parent"].Select("name = 'ParentB'")[0];
dr.Delete();

//  if constraints work, there should be
//  multiple Child and SubChild rows affected
var childChanges = dsSample.Tables["Child"].GetChanges(DataRowState.Deleted);
var subChanges = dsSample.Tables["SubChild"].GetChanges(DataRowState.Deleted);

Console.WriteLine("Child changes: {0},  subCh changes: {1}",
                        childChanges.Rows.Count,
                        subChanges.Rows.Count);

Result: 结果:

Child changes: 3, subCh changes: 4 子更改:3,subCh更改:4

Perfect! 完善! Deleting a single parent row cascades to also delete the 3 child rows which in turn deletes 4 subchild rows. 删除单个父行也会级联删除3个子行,这又会删除4个子行。 Take care that there are rows at each level - if there are no related subchild rows, you'll get a NulLReferenceException on subChanges.Rows.Count . 注意在每个级别上都有行-如果没有相关的子子行, NulLReferenceExceptionsubChanges.Rows.Count上获得subChanges.Rows.Count

Updating Database 更新数据库

This entails getting the changes and applying them in order. 这需要获取更改并按顺序应用它们。 Normally, the DataAdapter applies all inserts, updates and deletes for you at once. 通常, DataAdapter一次为您应用所有插入,更新和删除。 That wont work without violating constraints, so use some code to apply the changes in order: 在不违反约束的情况下将无法工作,因此请使用一些代码按顺序应用更改:

// Assuming changes were applied on DS/DT rows, 
// changed rows should be duly marked, so just
// run the updates

// insert first

DataTable parentRows = dsSample.Tables["Parent"].GetChanges(DataRowState.Added);
DataTable childRows = dsSample.Tables["Child"].GetChanges(DataRowState.Added);
DataTable subChRows = dsSample.Tables["SubChild"].GetChanges(DataRowState.Added);

// dont Update the DS.Tables...it will try
// to do ALL pending changes
if (parentRows != null)
    daParent.Update(parentRows);

if (childRows != null)
    daChild.Update(childRows);

if (subChRows != null)
    daSubCh.Update(subChRows);

// then update..order doesnt matter
parentRows = dsSample.Tables["Parent"].GetChanges(DataRowState.Modified);
childRows = dsSample.Tables["Child"].GetChanges(DataRowState.Modified);
subChRows = dsSample.Tables["SubChild"].GetChanges(DataRowState.Modified);
if (parentRows != null)
    daParent.Update(parentRows);

if (childRows != null)
    daChild.Update(childRows);

if (subChRows != null)
    daSubCh.Update(subChRows);

// then deletes...in reverse order!
parentRows = dsSample.Tables["Parent"].GetChanges(DataRowState.Deleted);
childRows = dsSample.Tables["Child"].GetChanges(DataRowState.Deleted);
subChRows = dsSample.Tables["SubChild"].GetChanges(DataRowState.Deleted);
if (subChRows != null)
    daSubCh.Update(subChRows);

if (childRows != null)
    daChild.Update(childRows);

if (parentRows != null)
    daParent.Update(parentRows);

// our work is done...time for cheesecake
dsSample.AcceptChanges();

Be sure to process deletes in reverse order - subChild first on up to Parent rows. 请确保以相反的顺序处理删除操作-首先在子行(最多父行)上使用subChild。 If everything worked as intended, the Access query from before should now be empty: 如果一切按预期工作,以前的Access查询现在应该为空:

在此处输入图片说明

et voilà ! 等!


It is not possible to tell from that SQL what you are doing (or if the DB is even modeled correctly). 无法从该SQL知道您在做什么(或者是否正确建模了数据库)。 But it is doubtful you would need an adapter for each table - some look like lookups. 但是令人怀疑的是,您是否需要为每个表使用适配器-有些看起来像查找。 In that case, they could be helper classes/objects providing that service. 在这种情况下,它们可以是提供该服务的助手类/对象。

Resources 资源资源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM