假设我在同一个数据库中有两个独立的表,即Book和Cup表。我只使用主键(int)创建了两个,称为Id。然后,为了保持整洁,我将它们分成不同的项目并为两者创建FluentMigrations,它们将驻留在Book.Migrations.dll
和Cup.Migrations.dll
中。
现在我意识到也许我的书应该能够有一个名字,并创建一个新的迁移来添加一个名为name的列。我将此版本设置为201408111220(因此写入此时的时间戳),并将其命名为AddNameToBook。我应用此迁移并相应地更新数据库。
然后我意识到也许杯子应该有颜色。所以我在另一个项目中创建了一个新的迁移,版本为201408111221,并将其命名为AddColorToCup。我再次运行迁移,并更新数据库。
据我所知,到目前为止一切都应该正常。我不确定的是,如果我现在添加另一个迁移到Book,比如201408111224,应用它,然后尝试回滚。从现在开始,VersionInfo -table中存在来自其他程序集的版本201408111221
,FluentMigrator将如何处理这个问题?它会在我的脸上抛出错误,或者只是忽略该行,因为当前的程序集对它没有任何了解吗?
欢迎以这种方式使用FluentMigrator的其他评论(一个数据库有多个程序集)。
答案 0 :(得分:3)
我写了一个迁移加载器来帮助我做到这一点
public class MultiAssemblyMigrationLoader : IMigrationInformationLoader
{
public MultiAssemblyMigrationLoader(IMigrationConventions conventions, IEnumerable<Assembly> assemblies, string @namespace, IEnumerable<string> tagsToMatch)
: this(conventions, assemblies, @namespace, false, tagsToMatch)
{
}
public MultiAssemblyMigrationLoader(IMigrationConventions conventions, IEnumerable<Assembly> assemblies, string @namespace, bool loadNestedNamespaces, IEnumerable<string> tagsToMatch)
{
this.Conventions = conventions;
this.Assemblies = assemblies;
this.Namespace = @namespace;
this.LoadNestedNamespaces = loadNestedNamespaces;
this.TagsToMatch = tagsToMatch ?? new string[0];
}
public IMigrationConventions Conventions { get; private set; }
public IEnumerable<Assembly> Assemblies { get; private set; }
public string Namespace { get; private set; }
public bool LoadNestedNamespaces { get; private set; }
public IEnumerable<string> TagsToMatch { get; private set; }
public SortedList<long, IMigrationInfo> LoadMigrations()
{
var sortedList = new SortedList<long, IMigrationInfo>();
IEnumerable<IMigration> migrations = this.FindMigrations();
if (migrations == null) return sortedList;
foreach (IMigration migration in migrations)
{
IMigrationInfo migrationInfo = this.Conventions.GetMigrationInfo(migration);
if (sortedList.ContainsKey(migrationInfo.Version))
throw new DuplicateMigrationException(string.Format("Duplicate migration version {0}.", migrationInfo.Version));
sortedList.Add(migrationInfo.Version, migrationInfo);
}
return sortedList;
}
private IEnumerable<IMigration> FindMigrations()
{
IEnumerable<Type> types = new Type[] { };
foreach (var assembly in Assemblies)
{
types = types.Concat(assembly.GetExportedTypes());
}
IEnumerable<Type> source = types.Where(t =>
{
if (!Conventions.TypeIsMigration(t))
return false;
if (!Conventions.TypeHasMatchingTags(t, this.TagsToMatch))
return !Conventions.TypeHasTags(t);
return true;
});
if (!string.IsNullOrEmpty(Namespace))
{
Func<Type, bool> predicate = t => t.Namespace == Namespace;
if (LoadNestedNamespaces)
{
string matchNested = Namespace + ".";
predicate = t =>
{
if (t.Namespace != Namespace)
return t.Namespace.StartsWith(matchNested);
return true;
};
}
source = source.Where(predicate);
}
return source.Select(matchedType => (IMigration)matchedType.Assembly.CreateInstance(matchedType.FullName));
}
}
要使用此类,您只需将其连接到MigrationRunner
即可 var runner = new MigrationRunner(mainAssembly, runnerContext, processor);
runner.MigrationLoader = new MultiAssemblyMigrationLoader(runner.Conventions, assemblies, runnerContext.Namespace, runnerContext.NestedNamespaces, runnerContext.Tags);
runner.MigrateUp(true);
答案 1 :(得分:2)
我不推荐这种方法。回滚或向上迁移时,VersionInfo表中保存的迁移版本与FluentMigrator程序集中的迁移版本不匹配。运气不好会崩溃。
如果您想要两个单独的项目,那么您需要两个VersionInfo表。其中一个项目可以使用默认的VersionInfo表,但另一个项目必须创建一个自定义的项目。请参阅here on how to create custom meta data for the VersionInfo table。
对于FluentMigrator,这与拥有两个数据库相同。当与模式结合时,这种方法很常见。在您的示例中,您将在数据库中创建Book模式和Cup模式,并使它们彼此分离。
根据我的经验,大多数数据库都不足以证明这个额外的开销,但如果你有数百或数千个迁移,那么你绝对应该将它分成不同的项目(并将数据库划分为不同的模式)。