【问题标题】:Overriding a DataModel inside a DLL覆盖 DLL 中的 DataModel
【发布时间】:2021-05-02 09:57:27
【问题描述】:

我正在开发一个新的 MVC 项目,基本上是一个我打算在其他项目中使用的 CMS,结构如下

假设我创建了一个使用我的 CMS 的 DLL 的新项目,尽管客户需要根据其他标准向模型添加新表,但覆盖 EcomerceModel.edmx 以便我可以工作的最佳方法是什么使用新添加的表格,而无需触及新创建项目中的原始 Dll。

谢谢,

【问题讨论】:

标签: c# asp.net asp.net-mvc content-management-system edmx


【解决方案1】:

嗯,有一个快速的解决方案,将您的 Data 项目分成几个项目,以保持最低要求。

因此,如果我们以您的 Data 项目为例,它将被分成几个类库,例如:

  • Data.Models(仅包含用于抽象目的的数据模型)。​​
  • Data.Core(主要数据项目)。
  • Data.Common(可选)
  • Data.Helpers(可选)

为此,您可能需要切换到Code First 方法,以确保您可以控制您的迁移和模型。 (每次更新模型时,您都不需要 EF 覆盖您的自定义设置,而且您需要将更新保存在代码中而不是数据库中)。

建议将模型保存在单独的程序集中,以便在其他项目中重复使用,而无需引用完整的数据层。

在此之后,在您的 Data.Core 中,您需要将所有其他 Data.* 类库引用到它。然后,您可以像这样创建您的DbContext

public class ECommerceDbContext : DbContext 
{
    public DbSet<Admin> Admins { get; set; }
    
    /// rest of Entities 
    

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        
        // your Entities configurations 
    }   
}

现在,您的Data 层已设置好,可以在其他项目中引用。

在您想要重用当前Data.Core 的其他项目中,您需要引用Data.Core(通过项目引用或Nuget)。然后,创建一个继承 ECommerceDbContext 的新类,该类将对其进行扩展。类似的东西:

public class ECommerceCMSContext : ECommerceDbContext 
{
    /// New Entities 
    

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        
        // New Entities configurations 
    }   
}

现在,使用ECommerceCMSContext 将任何新表添加到当前上下文中。

附:你可以看看ASP.NET Core Identity他们正在使用类似的实现,这对你的工作很有帮助。

【讨论】:

    【解决方案2】:

    您的问题并不容易回答。您要求在编程级别上进行数据映射,并且取决于您想要克服/处理多少变化将确定答案必须有多复杂。这也可以看作是模型继承。

    首先,edmx 文件对于您想要做的事情毫无用处。它将业务模型与数据模型相结合,这意味着对数据或业务模型的任何更改都会导致文件损坏。

    以下两个选项都需要大量工作,并且在大小方面应该被视为一个全新的应用程序。

    元数据解决方案

    您可能希望考虑在代码中创建元数据/数据层并使用它来更改数据库的外观。

    不是通过 ecommerce.edmx 访问模型,而是通过单独的业务/数据层访问它。然后,数据层可以使用动态调用或使用外部首选项文件来保存 sql 访问来创建数据访问/sql。

    即 在数据库中创建外部文件、表或代码中的资源,其中包含描述要使用的表的元数据。一个非常简单的解决方案可能如下所示:

    MetaTables (id, myTableName, derivedTableName)
        Order, "Order", "UserOrder"
        Customer, "Customer", "UserCustomer"
    
    MetaAttributes (tableId, id, myAttrName, myAttrType, derivedAttrName, derivedType, etc)
        Order, Id, "Id", int, "UserId", guid
        Order, Description, "Description", string, "UserDescription", string
        Customer, Id, "Id", int, "UserId", guid
    
    MetaRelations ()
        etc
    

    然后使用它来动态创建您的查询。如果您这样做,其他人可以使用您的代码,并且只需要使用新映射更新您的元数据文件。只要他们不添加新的必填列。

    优势:

    • 可以快速处理任何新的数据结构
    • 如果需要,可以随时更改数据结构
    • 版本无关

    弱点:

    • 动态创建的查询可能非常慢
    • 实现动态数据层需要很长时间

    反射解决方案

    另一种方法是将数据层存储在单独的程序集中并使用接口引用它。

    所有新应用程序需要做的就是用他们的数据层替换您的数据层。

    public interface IDataLayer
    {
        public List<IOrder> GetOrderList()
    }
    
    // MyDLL1
    public class DataLayerImplementationA: IDataLayer
    {
        public List<IOrder> GetOrderList()
        {
            // get data from database X, return results
        }
    }
    
    // MyDLL2
    public class DataLayerImplementationB: IDataLayer
    {
        public List<IOrder> GetOrderList()
        {
            // get data from database B, return results
        }
    }
    

    优势:

    • 代码设计用于新数据库
    • 最快的实现
    • 编译时检查!

    弱点:

    • 需要用新编译的 DLL 覆盖程序集
    • 多个 DLL
    • 即使是很小的更改也可能需要程序员进行大量编码(或至少剪切和粘贴)

    解决方法

    如果修改非常简单,您可以编写一个解析器来编辑 edmx 文件中的映射数据。不推荐,因为这可能会导致不稳定。

    另一种解决方法可能包括使用数据库视图隐藏更改并将数据更改处理移至数据库。因此,请让旧 edmx 文件查看视图,使用扩展设计的新 edmx 文件查看扩展表。

    变通办法就是这样......除了最微不足道的变化之外,它们可能会比它们所值得的更痛苦。

    如果您想做一些研究,请查看使用类似术语的文章

    • 面向对象的概念
    • 抽象数据层
    • 模型继承
    • 模型控制器视图

    狩猎愉快!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多