Code Monkey home page Code Monkey logo

Comments (1)

Kurris avatar Kurris commented on September 28, 2024

抱歉回复慢了
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 photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.