CREATE OR ALTER PROCEDURE spGetWeatherForecast
(
@location NVARCHAR(50)
)
AS
BEGIN
SELECT
Date,
Location,
TemperatureC Temperature,
Summary
FROM WeatherForecasts
WHERE LOWER(Location) = LOWER(@location)
END
CREATE OR ALTER FUNCTION fnGetTemperatureByLocation
(
@location NVARCHAR(50)
)
RETURNS INT
AS
BEGIN
DECLARE @Temperature INT
SELECT TOP(1)
@Temperature = TemperatureC
FROM WeatherForecasts
WHERE LOWER(Location) = LOWER(@location)
ORDER BY Id DESC
RETURN @Temperature
END
Build Action of those file should be Embedded resource- Right click on the file then select Property—
Now opening the Package Manager Console, will run following migration command—
add-migration v1_3 -c ApplicationDbContext -o Migrations
we could have add the SQL Scripts like bellow in our migration to generate migration script
namespace WeatherForecast.Infrastucture.Migrations
{
public partial class v1_3 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"'CREATE OR ALTER VIEW vwLocationTemperatureSummery
AS
SELECT
Date,
Location,
TemperatureC Temperature,
Summary
FROM WeatherForecasts'");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(string.Format(@"DROP VIEW IF EXISTS {0}", "vwLocationTemperatureSummery"));
}
}
}
But we will follow another approach so that we can create migration scripts dynamically from previously created scripts as well as those scripts can be tracked by the source control easily.
namespace WeatherForecast.Infrastucture.Migrations
{
public partial class v1_3 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RunSqlScript(View.LocationTemperatureSummery);
migrationBuilder.RunSqlScript(Procedure.GetWeatherInformation);
migrationBuilder.RunSqlScript(Function.GetTemperatureByLocation);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(string.Format(@"DROP VIEW IF EXISTS {0}", View.LocationTemperatureSummery));
migrationBuilder.Sql(string.Format(@"DROP PROCEDURE IF EXISTS {0}", Procedure.GetWeatherInformation));
migrationBuilder.Sql(string.Format(@"DROP FUNCTION IF EXISTS dbo.{0}", Function.GetTemperatureByLocation));
}
}
}
Here RunSqlScript is an Extention funtion that takes the script name as parameter to generate the script—
namespace WeatherForecast.Infrastucture.Extensions
{
public static class MigrationExtension
{
public static void RunSqlScript(this MigrationBuilder migrationBuilder, string script)
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = assembly.GetManifestResourceNames().FirstOrDefault(x => x.EndsWith($"{script}.sql"));
using var stream = assembly.GetManifestResourceStream(resourceName);
using var reader = new StreamReader(stream);
var sqlResult = reader.ReadToEnd();
migrationBuilder.Sql(sqlResult);
}
}
}
Besides this, we will use constants to keep the name of View, Procedure and Function because this name needs to be used in many places.
public class View
{
///
/// vwLocationTemperatureSummery
///
public const string LocationTemperatureSummery = "vwLocationTemperatureSummery";
}
public class Function
{
///
/// fnGetTemperatureByLocation(@location nvarchar) returns int
///
public const string GetTemperatureByLocation = "fnGetTemperatureByLocation";
}
public class Procedure
{
///
/// spGetWeatherInformation(@location nvarchar(50))
///
public const string GetWeatherInformation = "spGetWeatherInformation";
}
Now to generate the migration script, run the following command—
Script-Migration location-added v1_3 -c ApplicationDbContext -o Services/WeatherForecast/WeatherForecast.Infrastucture/Migrations/Scripts/v1.3.sql -i
-o = output location
-c = db-context
From location-added to v1_3
-i = Generate a script that can be used on a database at any migration
BEGIN TRANSACTION;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20221031051328_v1_3')
BEGIN
CREATE OR ALTER VIEW vwLocationTemperatureSummery
AS
SELECT
Date,
Location,
TemperatureC Temperature,
Summary
FROM WeatherForecasts
END;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20221031051328_v1_3')
BEGIN
CREATE OR ALTER PROCEDURE spGetWeatherForecast(@location nvarchar(50))
AS
SELECT
Date,
Location,
TemperatureC Temperature,
Summary
FROM WeatherForecasts
WHERE LOWER(Location) = LOWER(@location)
END;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20221031051328_v1_3')
BEGIN
CREATE OR ALTER FUNCTION fnGetTemperatureByLocation
(
@location NVARCHAR(50)
)
RETURNS int
AS
BEGIN
DECLARE @Temperature int
SELECT TOP(1)
@Temperature = TemperatureC
FROM WeatherForecasts
WHERE LOWER(Location) = LOWER(@location)
ORDER BY Id DESC
RETURN @Temperature
END
END;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20221031051328_v1_3')
BEGIN
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20221031051328_v1_3', N'6.0.4');
END;
GO
COMMIT;
GO
But this script show some syntax error—
So that we will add some modification maually and script sould be like folllowing—
BEGIN TRANSACTION;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20221031051328_v1_3')
BEGIN
EXEC(N' CREATE OR ALTER VIEW vwLocationTemperatureSummery
AS
SELECT
Date,
Location,
TemperatureC Temperature,
Summary
FROM WeatherForecasts')
END;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20221031051328_v1_3')
BEGIN
EXEC(N' CREATE OR ALTER PROCEDURE spGetWeatherForecast(@location nvarchar(50))
AS
SELECT
Date,
Location,
TemperatureC Temperature,
Summary
FROM WeatherForecasts
WHERE LOWER(Location) = LOWER(@location)')
END;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20221031051328_v1_3')
BEGIN
EXEC(N' CREATE OR ALTER FUNCTION fnGetTemperatureByLocation
(
@location NVARCHAR(50)
)
RETURNS int
AS
BEGIN
DECLARE @Temperature int
SELECT TOP(1)
@Temperature = TemperatureC
FROM WeatherForecasts
WHERE LOWER(Location) = LOWER(@location)
ORDER BY Id DESC
RETURN @Temperature
END')
END;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20221031051328_v1_3')
BEGIN
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20221031051328_v1_3', N'6.0.4');
END;
GO
COMMIT;
GO
Run the script and see the output—
Migration is done, Now we will create Dtos against our View, Procedure and Functions as well as map them in DbContext.
public class ApplicationDbContext: DbContext, IApplicationDbContext
{
public ApplicationDbContext()
{
}
#region TABLES
public DbSet WeatherForecasts => Set();
#endregion
#region VIEWS
///
/// vwLocationTemperatureSummery
///
public DbSet LocationTemperatureSummery => Set();
#endregion
#region PROCEDURES
///
/// spGetWeatherInformation(@location nvarchar(50)
///
public DbSet GetWeatherInformation => Set();
#endregion
#region FUNCTIONS
///
/// fnGetTemperatureByLocation(@location nvarchar(50)
///
public DbSet GetTemperatureByLocation => Set();
#endregion
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
base.OnModelCreating(builder);
#region VIEWS
builder.Entity(x =>
{
x.HasNoKey();
x.ToView(View.LocationTemperatureSummery);
x.Metadata.SetIsTableExcludedFromMigrations(true);
});
#endregion
#region FUNCTIONS
builder.Entity(x =>
{
x.HasNoKey();
x.ToFunction(Function.GetTemperatureByLocation);
x.Metadata.SetIsTableExcludedFromMigrations(true);
});
#endregion
#region PROCEDURES
builder.Entity(x =>
{
x.HasNoKey();
x.ToView(Procedure.GetWeatherInformation);
x.Metadata.SetIsTableExcludedFromMigrations(true);
});
#endregion
}
}
all are done, now test with running following code—
var locationTemp = await _context
.LocationTemperatureSummery
.Where(x => x.Location == request.Location)
.ToListAsync();
var location = new SqlParameter("location", System.Data.SqlDbType.NVarChar);
location.Value = request.Location;
// procedure
var weatherInfo = await _context
.GetWeatherInformation
.FromSqlRaw($"EXEC dbo.{Procedure.GetWeatherInformation} @location", location)
.ToListAsync();
// function
var temp = (await _context
.GetTemperatureByLocation
.FromSqlRaw($"SELECT dbo.{Function.GetTemperatureByLocation}(@location) Temperature", location)
.FirstOrDefaultAsync())!.Temperature;
Pattern Matching Expression
Hope this will help to track non-table database objects by source controll and make easy to use of non-table database like View, Procedure and Function.
Thanks with Source.