Как изменить датасет

Short Version How do i call: dataset1.FieldByName(fieldName).AsString := 'Something'; and have it work? Long version I have a DataSet: var ds: TDataSet; ds := GetSomeSortOfDataSetFromSome...

Short Version

How do i call:

dataset1.FieldByName(fieldName).AsString := 'Something';

and have it work?

Long version

I have a DataSet:

var
    ds: TDataSet;

    ds := GetSomeSortOfDataSetFromSomewhere();

This dataset will be exported (e.g. to Excel, cSV, TSV, Markdown, HTML, XML):

ExportDataSet(ds);

and the export will contain all columns and all rows:

Username Fullname
ian IAN BOYD
MartynA MARTIN
ngal NASREDDINE GALFOUT
uewr UWE RAABE

Now i want to modify the Fullname field for each row in-memory before doing something else with it (i.e. it’s never going back into a database, i don’t know where it came from , it might not have come from a database):

while not ds.EOF do
begin
    ds.FieldByName('Fullname').AsString := FormatNamePrettyLike(ds.FieldByName('Fullname').AsString;
    ds.Next;
end;

Trying to modify a field gives the exception:

Dataset not in edit or insert mode

The solution is to clone the dataset into an in-memory TClientDataset:

///<summary>Clones a dataset into a TClientDataSet; which is an editable in-memory DataSet.</summary>
function CloneDataSet(dsSource: TDataSet): TDataSet; //TDataSet > TCustomClientDataSet > TClientDataSet
var
    tempProvider: TDataSetProvider;
    data: OleVariant;
    ds: TClientDataSet;
begin
    tempProvider := TDataSetProvider.Create(nil);
    try
        tempProvider.DataSet := dsSource;
        data := tempProvider.Data;
    finally
        tempProvider.Free;
    end;

    ds := TClientDataSet.Create(nil);
    ds.Data := data;

    Result := ds;
end;

Which gives larger code:

var
   ds: TDataset;
   dsEditable: TDataSet;

   ds := GetDataSomeOfSomeSortFromSomewhere();

   //Clone to dataset to an in-memory dataset so we can modify it.
   dsEditable := CloneDataSet(ds);
   ds.Free;
   ds := edEditable;

   while not ds.EOF do
   begin
       ds.FieldByName('Fullname').AsString := FormatNamePrettyLike(ds.FieldByName('Fullname').AsString;
       ds.Next;
    end;

But this gives the error:

Dataset not in edit or insert mode

The solution is to put the dataset in edit mode:

//The in-memory ClientDataSet won't be editable until you mark it editable.
ds.Edit; 
///<summary>Clones a dataset into a TClientDataSet; which is an editable in-memory DataSet.</summary>
function CloneDataSet(dsSource: TDataSet): TDataSet; //TDataSet > TCustomClientDataSet > TClientDataSet
var
    tempProvider: TDataSetProvider;
    data: OleVariant;
    ds: TClientDataSet;
begin
    tempProvider := TDataSetProvider.Create(nil);
    try
        tempProvider.DataSet := dsSource;
        data := tempProvider.Data;
    finally
        tempProvider.Free;
    end;

    ds := TClientDataSet.Create(nil);
    ds.Data := data;

    //The in-memory ClientDataSet won't be editable until you mark it editable.
    ds.Edit;

    Result := ds;
end;

Repeating the excerise now gives the error:

Field Fullname cannot be modified.

The solution is to set Field.ReadOnly to false:

//Even after marking the in-memory data-set as editable, you still can't edit it 
//until you mark all fields as editable.
for i := 0 to ds.FieldCount-1 do
   ds.Fields[i].ReadOnly := False;
///<summary>Clones a dataset into a TClientDataSet; which is an editable in-memory DataSet.</summary>
function CloneDataSet(dsSource: TDataSet): TDataSet; //TDataSet > TCustomClientDataSet > TClientDataSet
var
    tempProvider: TDataSetProvider;
    data: OleVariant;
    ds: TClientDataSet;
begin
    tempProvider := TDataSetProvider.Create(nil);
    try
        tempProvider.DataSet := dsSource;
        data := tempProvider.Data;
    finally
        tempProvider.Free;
    end;

    ds := TClientDataSet.Create(nil);
    ds.Data := data;

    //The in-memory ClientDataSet won't be editable until you mark it editable.
    ds.Edit;

    //Even after marking the in-memory data-set as editable, you still can't edit it 
    //until you mark all fields as editable.
    for i := 0 to ds.FieldCount-1 do
        ds.Fields[i].ReadOnly := False;

    Result := ds;
end;

Repeating the exercise gives the error:

Trying to modify read-only field.

So i give up. How do i edit a DataSet field?

The cloned in-memory TCustomClientDataSet contents are all there; i just want to edit them on the client for display purposes.

Bonus Chatter

Obviously i can’t be adding new columns to the data set:

Username Fullname PrettyFullname
ian IAN BOYD Ian Boyd
MartynA MARTIN Martin
ngal NASREDDINE GALFOUT Nasreddine Galfout
uewr UWE RAABE Uwe Raabe

Obviously i can’t attach an event handler to the data set:

  • as that data handler would be invalid when the data set is passed onto the next person in a chain (e.g. a thread), and the original form is freed
  • and it’s also not what i’m asking; which is about modifying the contents of a data set
  • the updating of values hits other systems (e.g. databases, web-services, etc). I want the changes done once, and then in the data set

Последнее обновление: 14.02.2021

При работе с данными в DataSet мы можем производить с ними различными операции: удалять, изменять, добавлять новые записи. Но все производимые с данными изменения
автоматически не будут сохраняться в БД. Для этого нам еще надо вызвать метод Update объекта SqlDataAdapter,
который заполнял объект DataSet.

Для модификации данных в БД в соответствии с изменениями в DataSet SqlDataAdapter использует команды
InsertCommand, UpdateCommand и DeleteCommand. Мы можем сами определить для этих команд
sql-выражения, либо мы можем воспользоваться классом SqlCommandBuilder, который позволяет автоматически сгенерировать нужные выражения.

Например, добавим в DataSet строку, изменим уже имеющиеся данные и используем SqlCommandBuilder для сохранения объектов в базу данных:

using System;
using System.Data;
using Microsoft.Data.SqlClient;

namespace HelloApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string connectionString = "Server=(localdb)\mssqllocaldb;Database=adonetdb;Trusted_Connection=True;";
            string sql = "SELECT * FROM Users";
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                // Создаем объект DataAdapter
                SqlDataAdapter adapter = new SqlDataAdapter(sql, connection);
                // Создаем объект Dataset
                DataSet ds = new DataSet();
                // Заполняем Dataset
                adapter.Fill(ds);


                DataTable dt = ds.Tables[0];
                // добавим новую строку
                DataRow newRow = dt.NewRow();
                newRow["Name"] = "Rick";
                newRow["Age"] = 24;
                dt.Rows.Add(newRow);

                // Изменим значение в столбце Age для первой строки
                dt.Rows[0]["Age"] = 17;

                // создаем объект SqlCommandBuilder
                SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adapter);
                adapter.Update(ds);
                // альтернативный способ - обновление только одной таблицы
                //adapter.Update(dt);
                // заново получаем данные из бд
                // очищаем полностью DataSet
                ds.Clear();
                // перезагружаем данные
                adapter.Fill(ds);

                // Отображаем данные
                // перебор всех таблиц
                foreach (DataColumn column in dt.Columns)
                    Console.Write($"{column.ColumnName}t");
                Console.WriteLine();
                // перебор всех строк таблицы
                foreach (DataRow row in dt.Rows)
                {
                    // получаем все ячейки строки
                    var cells = row.ItemArray;
                    foreach (object cell in cells)
                        Console.Write($"{cell}t");
                    Console.WriteLine();
                }
            }
            Console.Read();
        }
    }
}

Консольный вывод в моем случае:

Id		Age		Name
2		17		Alice
3		28		Bob
19		36		Tom
22		34		Tim
23		31		Kate
24		26		Rick

Здесь после загрузки данных создается новая строка, которая затем добавляется в DataTable. При вызове у адаптера метода Update()
происходит анализ изменений, которые произошли. И после этого выполняется соответствующая команда. В данном случае так как идет добавление
новой строки, то будет выполняться команда InsertCommand. Однако в данном коде мы нигде явным образом не задаем эту команду, за нас все автоматически
делает SqlCommandBuilder. Для применения этого класса достаточно вызвать его конструктор, в который передается нужный адаптер:

SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adapter);

Причем больше нигде в коде вы этот объект не вызываем.

При необходимости мы можем получить sql-выражения используемых команд:

Console.WriteLine(commandBuilder.GetUpdateCommand().CommandText);
Console.WriteLine(commandBuilder.GetInsertCommand().CommandText);
Console.WriteLine(commandBuilder.GetDeleteCommand().CommandText);

В моем случае команда обновления будет выглядеть так:

UPDATE [Users] SET [Name]=@p1, [Age]=@p2 WHERE (([Id]=@p3) AND ([Name]=@p4) AND ([Age]=@p5))

Команда вставки:

INSERT INTO [Users] ([Name],[Age]) VALUES (@p1, @p2)

Команда удаления:

DELETE FROM [Users] WHERE (([Id]=@p1) AND ([Name]=@p2) AND ([Age]=@p3))

I have a Dataset with a TableAdapter and when i say something like this

this.medicineDatasetTableAdapter.Fill(this.statisticsDataset.MedicineDataset);

It brings me all the results from a database and i show them using a pivot from DevExpress control.
I am using sqlite as database and i store in a filed datetime eg ‘1/4/2012’ as string and when is the time to be show from the pivot with a grouping as DateMonth or whatever.. nothing is show up. I think that the pivot doesnt understand the format to group the dates..
Now i try to get the DataTable from the DataSet with the GetData command and change the datetime to a correct date and fill it again with the correct dates results.
One way i tryied is like

StatisticsDataset.MedicineDatasetDataTable datatable = this.medicineDatasetTableAdapter.GetData();

DataTable a = this.medicineDatasetTableAdapter.GetData();

foreach (DataRow row in a.Rows)
{
    DateTime tempDate = DateTime.ParseExact(row.ItemArray[4].ToString(), Resources.ShortDateFormat, new CultureInfo(Resources.CurrentCulture));
                row[4] = tempDate;
            }
            this.statisticsDataset.MedicineDataset = a;
            //this.medicineDatasetTableAdapter.Fill(this.statisticsDataset.MedicineDataset);
            this.medicineDatasetTableAdapter.Fill((MedExpress.Dataset.StatisticsDataset.MedicineDatasetDataTable)a);

But it doesnt works. Any suggestions please??

asked Mar 1, 2012 at 11:08

ddarellis's user avatar

Certainly seems to be a type issue.

Looking at the code you’re taking a data from a ‘Text’ cell, converting it into a DateTime and then copying the value back into the same ‘Text’ cell (which would cast the value back into a string!). I would suggest either…

  • Create a new strongly typed DateTime cell for your MedicineDatasetDataTable and copy the parsed value into that cell.

  • Why bother storing DateTime values as string, virtually all database products (sorry I’ve never used SQLLite) support this datatype and in a strongly typed scenario, there’s no need to convert values.

answered Mar 1, 2012 at 12:55

SeanCocteau's user avatar

SeanCocteauSeanCocteau

1,83819 silver badges25 bronze badges

1

I have a Dataset with a TableAdapter and when i say something like this

this.medicineDatasetTableAdapter.Fill(this.statisticsDataset.MedicineDataset);

It brings me all the results from a database and i show them using a pivot from DevExpress control.
I am using sqlite as database and i store in a filed datetime eg ‘1/4/2012’ as string and when is the time to be show from the pivot with a grouping as DateMonth or whatever.. nothing is show up. I think that the pivot doesnt understand the format to group the dates..
Now i try to get the DataTable from the DataSet with the GetData command and change the datetime to a correct date and fill it again with the correct dates results.
One way i tryied is like

StatisticsDataset.MedicineDatasetDataTable datatable = this.medicineDatasetTableAdapter.GetData();

DataTable a = this.medicineDatasetTableAdapter.GetData();

foreach (DataRow row in a.Rows)
{
    DateTime tempDate = DateTime.ParseExact(row.ItemArray[4].ToString(), Resources.ShortDateFormat, new CultureInfo(Resources.CurrentCulture));
                row[4] = tempDate;
            }
            this.statisticsDataset.MedicineDataset = a;
            //this.medicineDatasetTableAdapter.Fill(this.statisticsDataset.MedicineDataset);
            this.medicineDatasetTableAdapter.Fill((MedExpress.Dataset.StatisticsDataset.MedicineDatasetDataTable)a);

But it doesnt works. Any suggestions please??

asked Mar 1, 2012 at 11:08

ddarellis's user avatar

Certainly seems to be a type issue.

Looking at the code you’re taking a data from a ‘Text’ cell, converting it into a DateTime and then copying the value back into the same ‘Text’ cell (which would cast the value back into a string!). I would suggest either…

  • Create a new strongly typed DateTime cell for your MedicineDatasetDataTable and copy the parsed value into that cell.

  • Why bother storing DateTime values as string, virtually all database products (sorry I’ve never used SQLLite) support this datatype and in a strongly typed scenario, there’s no need to convert values.

answered Mar 1, 2012 at 12:55

SeanCocteau's user avatar

SeanCocteauSeanCocteau

1,83819 silver badges25 bronze badges

1

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить данные чужого сайта
  • Как изменить данные чипа собаки
  • Как изменить данные чипа на собаку
  • Как изменить данные файла mp3
  • Как изменить данные файла excel

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии