使 DAL 可扩展的模式/想法/经验

Posted

技术标签:

【中文标题】使 DAL 可扩展的模式/想法/经验【英文标题】:Patterns / Ideas / Experiences for making DAL extensible 【发布时间】:2012-07-18 11:53:06 【问题描述】:

我的任务是设计具有多租户 (SaaS) 服务器-客户端架构的应用程序,这是一项相当艰巨的任务。我已经考虑了一段时间服务器的内部架构,这就是我所拥有的:

我想让服务器在 WCF 或 MVC4 中实现 WebAPI。

服务器将具有基于插件的架构,使用 MEF 作为协调器。由于应用程序需要根据租户要求更改业务逻辑,因此我正在考虑这样做。更具体地说,我将有一个使用 MEF 导出的类/功能,并且在该类中,我将能够为托管它的 WebAPI 路由添加元数据属性。显然,在某些情况下,插件可能需要扩展,甚至可能被其他插件独占使用,在这种情况下,它们将没有路由。

此时我对服务器的主要问题是,我在某种程度上考虑了插件架构,插件应该能够处理插件需要的所有东西。所以在持久性方面,如果开发了一个新插件,我应该能够在插件中编写一些代码,然后可能由 DAL 执行以提供插件数据的持久性。我不希望插件在任何情况下都通过 DAL 并触摸数据库,因为多租户和访问的约束需要来自某个地方。从本质上讲,如果说 DAL 在 EF 上运行,我将如何选择在我的插件中定义一些持久性的能力。我考虑过将“CreatePersistentStorage(tenant)”之类的东西放到插件的界面中,让插件完全控制创建表。我相信 Orchard 会做类似的事情,但会以更强大的方式。

我需要有关如何实现可在插件内扩展的 DAL 的帮助。 DAL 必须控制最终的创建,因此插件的数据表是在正确的租户下创建的。

也许 EF 不适合?对您认为将不胜感激的评论/经验。此时你还会选择 WCF WebAPI 还是 ASP.NET WebAPI?

最好的问候, 拉里

【问题讨论】:

提示:msdn.microsoft.com/en-us/library/aa479086.aspx 解释了为多租户环境建模数据库的不同方法(并针对每个租户进行扩展)。 我也偶然发现了那篇文章,基于它我会选择共享数据库,分离模式方法。这是我发现的一篇使用 EF 实现的那种方法的文章:romiller.com/2011/05/23/ef-4-1-multi-tenant-with-code-first 【参考方案1】:

好的,这就是我目前所拥有的,它提供多租户,它提供插件 - 清洁度/优雅不是那么多。

public class Context : DbContext

    private static ConcurrentDictionary<string, DbCompiledModel> modelCache = 
               new ConcurrentDictionary<string, DbCompiledModel>();

    private Context(DbCompiledModel model) : base(model)
    
    

    public static Context Create(string tenantSchema)
    
        var compiledModel = modelCache.GetOrAdd(
            tenantSchema,
            t =>
                
                    var providerInfo = 
                        new DbProviderInfo("System.Data.SqlClient", "2008");
                    var modelBuilder = new DbModelBuilder();

                    modelBuilder.Conventions.Remove<IncludeMetadataConvention>();

                    foreach (var plugin in ServiceLocator
                        .Current
                        .GetAllInstances<IPlugin>().ToList())
                    
                        plugin.SetupPersistence(modelBuilder,tenantSchema);
                    

                    var model = modelBuilder.Build(providerInfo);
                    return model.Compile();
                );

        return new Context(compiledModel);
    

    /// <summary>
    /// Creates the database and/or tables for a new tenant
    /// </summary>
    public static void ProvisionTenant(string tenantSchema)
    
        using (var ctx = Create(tenantSchema))
        
            if (!ctx.Database.Exists())
            
                ctx.Database.Create();
            
            else
            
                try
                
                    var createScript = ((IObjectContextAdapter)ctx)
                        .ObjectContext
                        .CreateDatabaseScript();
                    ctx.Database.ExecuteSqlCommand(createScript);
                
                catch (Exception ex)
                
                    Console.WriteLine("Tenant already exists.");        
                
            
        
    

这是插件的外观:

[Export(typeof(IPlugin))]
public class Class2 : IPlugin


    public int Id  get; set; 
    public string Name  get; set; 
    public string Lol  get; set; 

    public void SetupPersistence(DbModelBuilder modelBuilder, string tenantSchema)
    
        modelBuilder.Entity<Class2>().ToTable("Keke", tenantSchema);
        modelBuilder.Entity<Class2>().HasKey(i => i.Id);
    

以下是您可以如何使用这些:

    Database.SetInitializer<Context>(null);

    Context.ProvisionTenant("personal");
    Context.ProvisionTenant("work");

    using (var db = Context.Create("personal"))
    
        db.Set<Class2>().Add(new Class2  Name = "Keke" );
        db.SaveChanges();
        foreach (var d in db.Set<Class2>())
        
            Console.WriteLine(d.Name);
        

        Console.Read();
    

我正在使用 CommonServiceLocator 来保存我的 MEF 参考。

现在,这有几个问题:

插件可以控制表名,并将模式名称设置为表 - 我不知道如何在 API 端控制它。我可以将整个 EF api 包装在另一个类中,但仅仅让一个函数按我想要的方式工作似乎很麻烦。 这样做的重点是要有一个插件可扩展的数据库层,而可扩展性的重点是为将来发生的更改做好准备,目前我的实现在更改部分还不够,因为没有处理插件内部迁移的方法。 太可怕了。

对于如何处理迁移或如何从上下文显式定义插件的表名,我们表示赞赏。

【讨论】:

以上是关于使 DAL 可扩展的模式/想法/经验的主要内容,如果未能解决你的问题,请参考以下文章

组合优于继承 - 如何使组件可扩展?

设计模式浅谈——抽象和解耦

可扩展的图像存储

SQL Server Express Edition 可扩展多远?

可扩展的菜单框(水平)

可扩展架构系统的探讨