Criando um DataTable de uma consulta (LINQ to DataSet)
A vinculação de dados é um uso comum do objeto DataTable. O método CopyToDataTable recebe os resultados de uma consulta e copia os dados em um DataTable, que podem ser usados para vinculação de dados. Quando as operações de dados tiverem sido executadas, o novo DataTable será mesclado de volta no DataTable de origem.
O método CopyToDataTable usa o seguinte processo para criar um DataTable de uma consulta:
O método CopyToDataTable clona um DataTable da tabela de origem (um objeto DataTable que implementa a interface IQueryable<T>). Em geral, a fonte do IEnumerable origina-se em uma expressão LINQ to DataSet ou consulta de método.
O esquema do DataTable clonado é criado de colunas do primeiro objeto DataRow enumerado na tabela de origem e o nome da tabela clonada é o nome da tabela de origem com a palavra “consulta” adicionada a ele.
Para cada linha na tabela de origem, o conteúdo da linha é copiado para um novo objeto DataRow, que é, em seguida, inserido na tabela clonada. As propriedades RowState e RowError são preservadas na operação de cópia. Um ArgumentException é gerado se os objetos DataRow na fonte forem de tabelas diferentes.
O DataTable clonado é retornado após todos os objetos DataRow na tabela consultável de entrada terem sido copiados. Se a sequência de origem não contiver nenhum objeto DataRow, o método retornará um DataTable vazio.
A chamada ao método CopyToDataTable fará com que a consulta associada à tabela de origem seja executada.
Quando o método CopyToDataTable encontrar uma referência nula ou o tipo de valor anulável em uma linha na tabela de origem, ele substituirá o valor por Value. Dessa maneira, os valores nulos serão manipulados corretamente no DataTable retornado.
Observação: o método CopyToDataTable aceita como entrada uma consulta que pode retornar linhas de vários objetos DataTable ou DataSet. O método CopyToDataTable copiará os dados mas não as propriedades dos objetos DataTable ou DataSet de origem para o DataTable retornado. Você precisará definir explicitamente as propriedades no DataTable retornado, por exemplo Locale e TableName.
O exemplo a seguir consulta a tabela SalesOrderHeader para pedidos após 8 de agosto de 2001 e usa o método CopyToDataTable para criar um DataTable a partir dessa consulta. O DataTable é então associado a um BindingSource, que age como o proxy para um DataGridView.
// Bind the System.Windows.Forms.DataGridView object
// to the System.Windows.Forms.BindingSource object.
dataGridView.DataSource = bindingSource;
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable orders = ds.Tables["SalesOrderHeader"];
// Query the SalesOrderHeader table for orders placed
// after August 8, 2001.
IEnumerable<DataRow> query =
from order in orders.AsEnumerable()
where order.Field<DateTime>("OrderDate") > new DateTime(2001, 8, 1)
select order;
// Create a table from the query.
DataTable boundTable = query.CopyToDataTable<DataRow>();
// Bind the table to a System.Windows.Forms.BindingSource object,
// which acts as a proxy for a System.Windows.Forms.DataGridView object.
bindingSource.DataSource = boundTable;
' Bind the System.Windows.Forms.DataGridView object
' to the System.Windows.Forms.BindingSource object.
dataGridView.DataSource = bindingSource
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)
Dim orders As DataTable = ds.Tables("SalesOrderHeader")
' Query the SalesOrderHeader table for orders placed
' after August 8, 2001.
Dim query = _
From order In orders.AsEnumerable() _
Where order.Field(Of DateTime)("OrderDate") > New DateTime(2001, 8, 1) _
Select order
' Create a table from the query.
Dim boundTable As DataTable = query.CopyToDataTable()
' Bind the table to a System.Windows.Forms.BindingSource object,
' which acts as a proxy for a System.Windows.Forms.DataGridView object.
bindingSource.DataSource = boundTable
Criação de um método CopyToDataTable<T>
Os métodos CopyToDataTable existentes somente funcionam em uma fonte de IEnumerable<T> onde o parâmetro genérico T
é do tipo DataRow. Embora isso seja útil, não permite que as tabelas sejam criadas de uma sequência de tipos escalares, de consultas que retornam tipos anônimos ou de consultas que executam uniões de tabela. Para obter um exemplo de como implementar dois métodos personalizados CopyToDataTable
que carreguem uma tabela de uma sequência de tipos escalares ou anônimos, consulte Como: Implementar CopyToDataTable<T> Onde o Tipo Genérico T Não É um DataRows.
Os exemplos nesta seção usam os seguintes tipos personalizados:
public class Item
{
public int Id { get; set; }
public double Price { get; set; }
public string Genre { get; set; }
}
public class Book : Item
{
public string Author { get; set; }
}
public class Movie : Item
{
public string Director { get; set; }
}
Public Class Item
Private _Id As Int32
Private _Price As Double
Private _Genre As String
Public Property Id() As Int32
Get
Return Id
End Get
Set(ByVal value As Int32)
_Id = value
End Set
End Property
Public Property Price() As Double
Get
Return _Price
End Get
Set(ByVal value As Double)
_Price = value
End Set
End Property
Public Property Genre() As String
Get
Return _Genre
End Get
Set(ByVal value As String)
_Genre = value
End Set
End Property
End Class
Public Class Book
Inherits Item
Private _Author As String
Public Property Author() As String
Get
Return _Author
End Get
Set(ByVal value As String)
_Author = value
End Set
End Property
End Class
Public Class Movie
Inherits Item
Private _Director As String
Public Property Director() As String
Get
Return _Director
End Get
Set(ByVal value As String)
_Director = value
End Set
End Property
End Class
Exemplo
Este exemplo realiza uma união das tabelas SalesOrderHeader
e SalesOrderDetail
para obter pedidos online do mês de agosto e cria uma tabela da consulta.
// Fill the DataSet.
var ds = new DataSet
{
Locale = CultureInfo.InvariantCulture
};
FillDataSet(ds);
DataTable orders = ds.Tables["SalesOrderHeader"];
DataTable details = ds.Tables["SalesOrderDetail"];
var query =
from order in orders.AsEnumerable()
join detail in details.AsEnumerable()
on order.Field<int>("SalesOrderID") equals
detail.Field<int>("SalesOrderID")
where order.Field<bool>("OnlineOrderFlag")
&& order.Field<DateTime>("OrderDate").Month == 8
select new
{
SalesOrderID =
order.Field<int>("SalesOrderID"),
SalesOrderDetailID =
detail.Field<int>("SalesOrderDetailID"),
OrderDate =
order.Field<DateTime>("OrderDate"),
ProductID =
detail.Field<int>("ProductID")
};
DataTable orderTable = query.CopyToDataTable();
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)
Dim orders As DataTable = ds.Tables("SalesOrderHeader")
Dim details As DataTable = ds.Tables("SalesOrderDetail")
Dim query = _
From order In orders.AsEnumerable() _
Join detail In details.AsEnumerable() _
On order.Field(Of Integer)("SalesOrderID") Equals _
detail.Field(Of Integer)("SalesOrderID") _
Where order.Field(Of Boolean)("OnlineOrderFlag") = True And _
order.Field(Of DateTime)("OrderDate").Month = 8 _
Select New With _
{ _
.SalesOrderID = order.Field(Of Integer)("SalesOrderID"), _
.SalesOrderDetailID = detail.Field(Of Integer)("SalesOrderDetailID"), _
.OrderDate = order.Field(Of DateTime)("OrderDate"), _
.ProductID = detail.Field(Of Integer)("ProductID") _
}
Dim table As DataTable = query.CopyToDataTable()
Exemplo
O exemplo a seguir consulta uma coleção em busca de itens de preço maior que US$9,99 e cria uma tabela dos resultados da consulta.
// Create a sequence.
var items = new Item[]
{ new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"},
new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},
new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},
new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};
// Query for items with price greater than 9.99.
IOrderedEnumerable<Item> query = from i in items
where i.Price > 9.99
orderby i.Price
select i;
// Load the query results into new DataTable.
DataTable table = query.CopyToDataTable();
Dim book1 As New Book()
book1.Id = 1
book1.Price = 13.5
book1.Genre = "Comedy"
book1.Author = "Gustavo Achong"
Dim book2 As New Book
book2.Id = 2
book2.Price = 8.5
book2.Genre = "Drama"
book2.Author = "Jessie Zeng"
Dim movie1 As New Movie
movie1.Id = 1
movie1.Price = 22.99
movie1.Genre = "Comedy"
movie1.Director = "Marissa Barnes"
Dim movie2 As New Movie
movie2.Id = 1
movie2.Price = 13.4
movie2.Genre = "Action"
movie2.Director = "Emmanuel Fernandez"
Dim items(3) As Item
items(0) = book1
items(1) = book2
items(2) = movie1
items(3) = movie2
' Query for items with price greater than 9.99.
Dim query = From i In items _
Where i.Price > 9.99 _
Order By i.Price _
Select New With {i.Price, i.Genre}
Dim table As DataTable
table = query.CopyToDataTable()
Exemplo
O exemplo a seguir consulta uma coleção em busca de itens de preço maior que US$9,99 e projeta os resultados. A sequência retornada de tipos anônimos é carregada em uma tabela existente.
// Create a sequence.
var items = new Item[]
{ new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"},
new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},
new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},
new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};
// Create a table with a schema that matches that of the query results.
var table = new DataTable();
table.Columns.Add("Price", typeof(int));
table.Columns.Add("Genre", typeof(string));
var query = from i in items
where i.Price > 9.99
orderby i.Price
select new { i.Price, i.Genre };
query.CopyToDataTable(table, LoadOption.PreserveChanges);
Dim book1 As New Book()
book1.Id = 1
book1.Price = 13.5
book1.Genre = "Comedy"
book1.Author = "Gustavo Achong"
Dim book2 As New Book
book2.Id = 2
book2.Price = 8.5
book2.Genre = "Drama"
book2.Author = "Jessie Zeng"
Dim movie1 As New Movie
movie1.Id = 1
movie1.Price = 22.99
movie1.Genre = "Comedy"
movie1.Director = "Marissa Barnes"
Dim movie2 As New Movie
movie2.Id = 1
movie2.Price = 13.4
movie2.Genre = "Action"
movie2.Director = "Emmanuel Fernandez"
Dim items(3) As Item
items(0) = book1
items(1) = book2
items(2) = movie1
items(3) = movie2
' Create a table with a schema that matches that of the query results.
Dim table As DataTable = New DataTable()
table.Columns.Add("Price", GetType(Integer))
table.Columns.Add("Genre", GetType(String))
' Query for items with price greater than 9.99.
Dim query = From i In items _
Where i.Price > 9.99 _
Order By i.Price _
Select New With {i.Price, i.Genre}
query.CopyToDataTable(table, LoadOption.PreserveChanges)
Exemplo
O exemplo a seguir consulta uma coleção em busca de itens de preço maior que US$9,99 e projeta os resultados. A sequência retornada de tipos anônimos é carregada em uma tabela existente. O esquema da tabela é automaticamente expandido porque os tipos Book
e Movies
são derivados do tipo Item
.
// Create a sequence.
var items = new Item[]
{ new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"},
new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},
new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},
new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};
// Load into an existing DataTable, expand the schema and
// autogenerate a new Id.
var table = new DataTable();
DataColumn dc = table.Columns.Add("NewId", typeof(int));
dc.AutoIncrement = true;
table.Columns.Add("ExtraColumn", typeof(string));
var query = from i in items
where i.Price > 9.99
orderby i.Price
select new { i.Price, i.Genre };
query.CopyToDataTable(table, LoadOption.PreserveChanges);
Dim book1 As New Book()
book1.Id = 1
book1.Price = 13.5
book1.Genre = "Comedy"
book1.Author = "Gustavo Achong"
Dim book2 As New Book
book2.Id = 2
book2.Price = 8.5
book2.Genre = "Drama"
book2.Author = "Jessie Zeng"
Dim movie1 As New Movie
movie1.Id = 1
movie1.Price = 22.99
movie1.Genre = "Comedy"
movie1.Director = "Marissa Barnes"
Dim movie2 As New Movie
movie2.Id = 1
movie2.Price = 13.4
movie2.Genre = "Action"
movie2.Director = "Emmanuel Fernandez"
Dim items(3) As Item
items(0) = book1
items(1) = book2
items(2) = movie1
items(3) = movie2
' Load into an existing DataTable, expand the schema and
' autogenerate a new Id.
Dim table As DataTable = New DataTable()
Dim dc As DataColumn = table.Columns.Add("NewId", GetType(Integer))
dc.AutoIncrement = True
table.Columns.Add("ExtraColumn", GetType(String))
Dim query = From i In items _
Where i.Price > 9.99 _
Order By i.Price _
Select New With {i.Price, i.Genre}
query.CopyToDataTable(table, LoadOption.PreserveChanges)
Exemplo
O exemplo a seguir consulta uma coleção em busca de itens de preço maior que US$9,99 e retorna uma sequência de Double, que é carregada em uma nova tabela.
// Create a sequence.
var items = new Item[]
{ new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"},
new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},
new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},
new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};
// load sequence of scalars.
IEnumerable<double> query = from i in items
where i.Price > 9.99
orderby i.Price
select i.Price;
DataTable table = query.CopyToDataTable();
Dim book1 As New Book()
book1.Id = 1
book1.Price = 13.5
book1.Genre = "Comedy"
book1.Author = "Gustavo Achong"
Dim book2 As New Book
book2.Id = 2
book2.Price = 8.5
book2.Genre = "Drama"
book2.Author = "Jessie Zeng"
Dim movie1 As New Movie
movie1.Id = 1
movie1.Price = 22.99
movie1.Genre = "Comedy"
movie1.Director = "Marissa Barnes"
Dim movie2 As New Movie
movie2.Id = 1
movie2.Price = 13.4
movie2.Genre = "Action"
movie2.Director = "Emmanuel Fernandez"
Dim items(3) As Item
items(0) = book1
items(1) = book2
items(2) = movie1
items(3) = movie2
Dim query = From i In items _
Where i.Price > 9.99 _
Order By i.Price _
Select i.Price
Dim table As DataTable
table = query.CopyToDataTable()