Comments (1)
抱歉回复慢了
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Kurisu.DataAccess.Extensions;
using Kurisu.DataAccess.Functions.Default;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Design;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.Extensions.DependencyInjection;
namespace Kurisu.DataAccess.Internal;
/**
*
*
*/
public static class MigrationExtensions
{
private const string Namespace = "DynamicMigrations";
private const string ClassName = "EfContentModelSnapshot";
private const string FullName = $"{Namespace}.{ClassName}";
/// <summary>
/// 动态迁移
/// </summary>
/// <param name="dbContext"></param>
public static async Task RunDynamicMigrationAsync(this DbContext dbContext)
{
IModel lastModel = null;
var now = DateTime.Now;
if (await dbContext.Database.IsTableExistsAsync(dbContext.Model.FindEntityType(typeof(AutoMigrationsHistory))!.GetTableName()))
{
// 读取迁移记录,还原modelSnapshot
var lastMigration = dbContext.Set<AutoMigrationsHistory>()
.AsNoTracking()
.OrderByDescending(x => x.Id)
.FirstOrDefault();
if (!string.IsNullOrEmpty(lastMigration?.SnapshotDefine))
{
var snapshot = CreateModelSnapshot(FullName, lastMigration.SnapshotDefine);
lastModel = snapshot.Model;
}
}
var differ = dbContext.GetService<IMigrationsModelDiffer>();
var lastRelationalModel = lastModel == null
? null
: dbContext.GetService<IModelRuntimeInitializer>()
.Initialize(((IMutableModel) lastModel).FinalizeModel())
.GetRelationalModel();
var currentRelationalModel = dbContext.GetService<IDesignTimeModel>().Model.GetRelationalModel();
//判断是否存在更改
if (differ.HasDifferences(lastRelationalModel, currentRelationalModel))
{
var operations = differ.GetDifferences(lastRelationalModel, currentRelationalModel);
//执行迁移
await dbContext.MigrationAsync(operations);
//生成新的快照
var snapshotCode = new DesignTimeServicesBuilder(typeof(DefaultAppDbContext).Assembly, Assembly.GetExecutingAssembly(), new OperationReporter(new OperationReportHandler()), Array.Empty<string>())
.Build(dbContext)
.GetRequiredService<IMigrationsCodeGenerator>()
.GenerateSnapshot(Namespace, typeof(DefaultAppDbContext), ClassName, currentRelationalModel.Model);
dbContext.Set<AutoMigrationsHistory>().Add(new AutoMigrationsHistory
{
SnapshotDefine = snapshotCode,
MigrationTime = now
});
await dbContext.SaveChangesAsync();
}
}
/// <summary>
/// 创建模型快照
/// </summary>
/// <param name="fullName"></param>
/// <param name="codeDefine"></param>
/// <returns></returns>
private static ModelSnapshot CreateModelSnapshot(string fullName, string codeDefine)
{
var references = typeof(DefaultAppDbContext).Assembly
.GetReferencedAssemblies()
.Select(e => MetadataReference.CreateFromFile(Assembly.Load(e).Location))
.Union(new MetadataReference[]
{
MetadataReference.CreateFromFile(Assembly.Load("netstandard").Location),
MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location),
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(DefaultAppDbContext).Assembly.Location)
});
var compilation = CSharpCompilation.Create(Namespace)
.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.AddReferences(references)
.AddSyntaxTrees(SyntaxFactory.ParseSyntaxTree(codeDefine));
using var stream = new MemoryStream();
var compileResult = compilation.Emit(stream);
if (compileResult.Success)
{
var obj = Assembly.Load(stream.GetBuffer()).CreateInstance(fullName);
return obj as ModelSnapshot;
}
return null;
}
/// <summary>
/// 迁移
/// </summary>
/// <param name="dbContext"></param>
/// <param name="operations"></param>
private static async Task MigrationAsync(this DbContext dbContext, IReadOnlyList<MigrationOperation> operations)
{
var sqlGenerator = dbContext.GetService<IMigrationsSqlGenerator>();
var list = sqlGenerator
.Generate(operations, dbContext.Model)
.Select(p => p.CommandText).ToList();
await dbContext.Database.ExecuteSqlRawAsync(string.Join(Environment.NewLine, list));
}
}
from kurisu.
Related Issues (1)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from kurisu.