【问题标题】:How to avoid using data access layer in presentation layer?如何避免在表示层使用数据访问层?
【发布时间】:2018-05-29 05:52:05
【问题描述】:

我有一个使用 Sqlite 进行 CRUD 操作的数据层,所以在我的 Sqlite 类中我必须传递数据库的路径,为此我在数据层中有接口 IConnectionProvider,如下所示:

public interface IConnectionProvider
 {
        string DbPath { get; }
 }

SqliteDb.cs

public class SQLiteDb : DbContext, IDbContext
    {
        internal const string DefaultDatabaseName = "My.db";

        private string connectionString = null;

        public SQLiteDb(IConnectionProvider connectionProvider)
        {
            this.connectionString = connectionProvider.DbPath;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite(connectionString);
        }
    }

我的项目架构如下:

 Data Layer -> View Model -> Presentation Layer

我想避免直接在表示层中使用数据层,但是要传递 DBPath 我必须添加它的引用。

下面是IConnectionProvider在我的表现层中的实现:

public class SqlConnectionProvider : IConnectionProvider
    {
        public string dbPath = string.Empty;
        public string DbPath
        {
            get
            {
                if (string.IsNullOrEmpty(dbPath))
                {
                    dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, "MyDb.sqlite");
                }

                return dbPath;
            }
        }
  }

有什么方法可以避免将 DataLayer 直接用于表示层?我想在 VM 中创建包装器,但我认为这不是一个好主意,因为它会创建更多的依赖项。

【问题讨论】:

  • 确定,注入并编程到数据层接口?除了简单地说“不要做你正在做的事”之外,你还不清楚你在问什么。

标签: c# design-patterns ninject


【解决方案1】:

执行此操作的常用方法是使用存储库模式。在 ViewModel 层中定义一个接口并在 DataLayer 中实现它。然后 ViewModel 对 DataLayer 一无所知。然后通过依赖注入在主类中使用 ConnectionProvider 实例化存储库。 dbContext 也必须移动到 DataLayer,您应该在存储库中使用它。我建议将连接字符串放在配置文件中并在 DL 中使用它。类应该是这样的

namespace ViewModel;
interface IDatabaseRepository {
   DataObject LoadData()
}

namespace DataLayer;
class DataRepository {
   public DataRepository(DbContext context) {
      this.context = context;
   }

   public DataObject LoadData() {
      //load data from DB using dbContext
   }
}

namespace ViewModel;
class ViewModel {
   public ViewModel(IDataRepository repository) {
      this.repository = repository;
   }

   // use the repository inside this class to acces data
}

还可以查看依赖倒置原则,因为这有助于解耦类似的事情。

【讨论】:

  • 谢谢,但我在 VM 中引用了 DL,在 PL 中引用了 VM,我必须提供来自 PL 而不是 VM 的路径。因此,您提到的方法不适用于我的情况。如果遗漏了什么,请纠正我。
  • Presentationlayer 应该对 ConnectionProvider 一无所知,因为它属于 DB 层。这可能是您遇到的唯一问题。我通常有一个额外的 DependencyInjection 项目,它初始化所有内容并了解每个项目。我习惯称这个项目为“主机”。你的切入点是在 PL 中吗?这不应该在那里,因为这需要 PL 知道太多。
  • 你是对的,但是 DB 的路径只能从 PL 生成,因为 DL 和 VM 没有 API 来获取应用程序路径。基本上我的 DL 和 VM 是 .Net Standard 2.0 而 PL 是 UWP App。所以从 UWP 应用程序我需要将 DBPath 传递给数据层。
  • 我宁愿在 DL 中使用硬编码字符串或从配置文件中读取它,也不愿在 PL 中生成。但是您可以将字符串从 PL 向下传递到数据库,而无需在 PL 中引用 DL。你如何在 PL 中生成这个字符串?我不知道 UWP 必须从数据库中了解任何内容的原因。如果您从 UWP 项目生成数据库,请通过另一个存储库和接口在视图模型中执行此操作。 UI 应该只知道该位置的字符串,但不知道使用该字符串的类。
  • 请参考我更新的答案,你可以看到我是如何在 PL 中生成 DbPath 以及它是如何在 SQliteDb.cs 的 DL 中使用的。但现在我正在使用“IConnectionProvider”,它是 PL 中 DL 的一部分,我想避免使用它。
猜你喜欢
  • 1970-01-01
  • 2010-11-03
  • 2014-04-23
  • 1970-01-01
  • 2011-10-20
  • 1970-01-01
  • 2014-07-31
  • 2014-10-01
相关资源
最近更新 更多