Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Data.Common;
using Microsoft.ML.Data;

namespace Microsoft.ML
Expand Down Expand Up @@ -38,5 +39,52 @@ public static DatabaseLoader CreateDatabaseLoader(this DataOperationsCatalog cat
/// <param name="catalog">The <see cref="DataOperationsCatalog"/> catalog.</param>
public static DatabaseLoader CreateDatabaseLoader<TInput>(this DataOperationsCatalog catalog)
=> DatabaseLoader.CreateDatabaseLoader<TInput>(CatalogUtils.GetEnvironment(catalog));

/// <summary>
/// Load an <see cref="IDataView"/> from a database using a <see cref="DatabaseLoader"/>.
/// Note that <see cref="IDataView"/>'s are lazy, so no actual loading happens here, just schema validation.
/// </summary>
/// <typeparam name="TInput">Defines the schema of the data to be loaded. Use public fields or properties
/// decorated with <see cref="LoadColumnAttribute"/> (and possibly other attributes) to specify the column
/// names and their data types in the schema of the loaded data.</typeparam>
/// <param name="catalog">The <see cref="DataOperationsCatalog"/> catalog.</param>
/// <param name="source">The <see cref="DatabaseSource"/> containing the connection and command information.</param>
/// <returns>The data view.</returns>
public static IDataView LoadFromDatabase<TInput>(this DataOperationsCatalog catalog,
DatabaseSource source)
=> catalog.CreateDatabaseLoader<TInput>().Load(source);

/// <summary>
/// Load an <see cref="IDataView"/> from a database using a <see cref="DatabaseLoader"/>.
/// Note that <see cref="IDataView"/>'s are lazy, so no actual loading happens here, just schema validation.
/// </summary>
/// <typeparam name="TInput">Defines the schema of the data to be loaded. Use public fields or properties
/// decorated with <see cref="LoadColumnAttribute"/> (and possibly other attributes) to specify the column
/// names and their data types in the schema of the loaded data.</typeparam>
/// <param name="catalog">The <see cref="DataOperationsCatalog"/> catalog.</param>
/// <param name="providerFactory">The factory used to create the <see cref="DbConnection"/>.</param>
/// <param name="connectionString">The string used to open the connection.</param>
/// <param name="commandText">The text command to run against the data source.</param>
/// <returns>The data view.</returns>
public static IDataView LoadFromDatabase<TInput>(this DataOperationsCatalog catalog,
DbProviderFactory providerFactory, string connectionString, string commandText)
=> catalog.LoadFromDatabase<TInput>(new DatabaseSource(providerFactory, connectionString, commandText));

/// <summary>
/// Load an <see cref="IDataView"/> from a database using a <see cref="DatabaseLoader"/>.
/// Note that <see cref="IDataView"/>'s are lazy, so no actual loading happens here, just schema validation.
/// </summary>
/// <typeparam name="TInput">Defines the schema of the data to be loaded. Use public fields or properties
/// decorated with <see cref="LoadColumnAttribute"/> (and possibly other attributes) to specify the column
/// names and their data types in the schema of the loaded data.</typeparam>
/// <param name="catalog">The <see cref="DataOperationsCatalog"/> catalog.</param>
/// <param name="providerFactory">The factory used to create the <see cref="DbConnection"/>.</param>
/// <param name="connectionString">The string used to open the connection.</param>
/// <param name="commandText">The text command to run against the data source.</param>
/// <param name="commandTimeoutInSeconds">The timeout (in seconds) for the database command.</param>
/// <returns>The data view.</returns>
public static IDataView LoadFromDatabase<TInput>(this DataOperationsCatalog catalog,
DbProviderFactory providerFactory, string connectionString, string commandText, int commandTimeoutInSeconds)
=> catalog.LoadFromDatabase<TInput>(new DatabaseSource(providerFactory, connectionString, commandText, commandTimeoutInSeconds));
}
}
47 changes: 47 additions & 0 deletions test/Microsoft.ML.Tests/DatabaseLoaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,53 @@ public void IrisLightGbmWithLoadColumnName()
}).PredictedLabel);
}

[X86X64FactAttribute("The SQLite un-managed code, SQLite.interop, only supports x86/x64 architectures.")]
public void LoadFromDatabaseLoadsExpectedData()
{
// Use an in-memory SQLite database so the test is fast and self-contained.
var connectionString = "DataSource=LoadFromDatabaseTest;Mode=Memory;Version=3;Timeout=120;Cache=Shared";
using (var connection = new SQLiteConnection(connectionString))
{
connection.Open();
using (var command = new SQLiteCommand(connection))
{
command.CommandText = """
BEGIN;
DROP TABLE IF EXISTS Iris;
CREATE TABLE IF NOT EXISTS Iris (Label INTEGER, SepalLength REAL, SepalWidth REAL, PetalLength REAL, PetalWidth REAL);
INSERT INTO Iris VALUES (0, 4.5, 5.6, 0.5, 0.5);
INSERT INTO Iris VALUES (1, 4.9, 2.4, 3.3, 1.0);
COMMIT;
""";
command.ExecuteNonQuery();
}

var mlContext = new MLContext(seed: 1);

// LoadFromDatabase combines CreateDatabaseLoader<TInput>() and Load(DatabaseSource)
// into a single call. Exercise both the DatabaseSource overload and the
// DbProviderFactory arguments overload; both should load identical data.
var source = new DatabaseSource(SQLiteFactory.Instance, connectionString, "SELECT * FROM Iris");
var loadedFromSource = mlContext.Data.LoadFromDatabase<IrisVectorData>(source);
var loadedFromArgs = mlContext.Data.LoadFromDatabase<IrisVectorData>(SQLiteFactory.Instance, connectionString, "SELECT * FROM Iris");

foreach (var data in new[] { loadedFromSource, loadedFromArgs })
{
var rows = mlContext.Data.CreateEnumerable<IrisVectorData>(data, reuseRowObject: false).ToArray();

rows.Length.Should().Be(2);

rows[0].Label.Should().Be(0);
rows[0].SepalInfo.Should().Equal(4.5f, 5.6f);
rows[0].PetalInfo.Should().Equal(0.5f, 0.5f);

rows[1].Label.Should().Be(1);
rows[1].SepalInfo.Should().Equal(4.9f, 2.4f);
rows[1].PetalInfo.Should().Equal(3.3f, 1.0f);
}
}
}

[LightGBMFact]
public void IrisVectorLightGbm()
{
Expand Down
Loading