C# 如何避免在表示层中使用数据访问层?

C# 如何避免在表示层中使用数据访问层?,c#,design-patterns,ninject,C#,Design Patterns,Ninject,我有一个数据层,它使用Sqlite进行CRUD操作,因此在我的Sqlite类中,我必须传递DB的路径,为此,我在数据层中有接口IConnectionProvider,如下所示: public interface IConnectionProvider { string DbPath { get; } } Data Layer -> View Model -> Presentation Layer SqliteDb.cs public class SQLite

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

public interface IConnectionProvider
 {
        string DbPath { get; }
 }
 Data Layer -> View Model -> Presentation Layer
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);
        }
    }
我的项目架构如下:

public interface IConnectionProvider
 {
        string DbPath { get; }
 }
 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;
            }
        }
  }

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

通常的方法是使用存储库模式。在ViewModel层中定义一个接口,并在数据层中实现它。那么ViewModel对数据层一无所知。然后通过依赖项注入在主类中使用ConnectionProvider实例化存储库。此外,dbContext必须移动到数据层,您应该在存储库中使用它。我建议将连接字符串放在配置文件中,并在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标准2.0,PL是UWP应用程序。因此,从UWP应用程序中,我需要将DBPath传递到数据层。我宁愿将硬编码字符串保存在DL中,或者从配置文件中读取它,也不愿在PL中生成。但是,您可以将字符串从PL向下传递到数据库,而无需在PL中引用DL。如何在PL中生成此字符串?我不知道为什么UWP必须从数据库中知道任何东西。如果您从UWP项目生成DB,那么也可以通过另一个存储库和接口在viewmodel中进行。UI应该只知道指向该位置的字符串,而不知道使用该字符串的类。请参考我更新的答案,您可以看到我是如何在PL中生成DbPath的,以及它是如何在SQliteDb.cs的DL中使用的。但现在我正在使用“IConnectionProvider”,它是PL中DL的一部分,我希望避免使用它。