首先,我认为这样做有点荒谬,但我的团队其他成员坚持要这么做,而我无法提出好的反对理由,除了“我觉得这很蠢”...
我们试图做的是创建一个完全抽象的数据层,然后有不同的数据层实现。这很简单,对吧? 进入Entity Framework 4.1...
我们的最终目标是程序员(我尽力只留在数据层)从未想要暴露给具体类。他们只想在代码中使用接口,除了明显需要实例化工厂之外。
我想要实现以下内容:
首先,我们有所有接口的“Common”库,我们将其称为“Common.Data”:
我们试图做的是创建一个完全抽象的数据层,然后有不同的数据层实现。这很简单,对吧? 进入Entity Framework 4.1...
我们的最终目标是程序员(我尽力只留在数据层)从未想要暴露给具体类。他们只想在代码中使用接口,除了明显需要实例化工厂之外。
我想要实现以下内容:
首先,我们有所有接口的“Common”库,我们将其称为“Common.Data”:
public interface IEntity
{
int ID { get; set; }
}
public interface IUser : IEntity
{
int AccountID { get; set; }
string Username { get; set; }
string EmailAddress { get; set; }
IAccount Account { get; set; }
}
public interface IAccount : IEntity
{
string FirstName { get; set; }
string LastName { get; set; }
DbSet<IUser> Users { get; set; } // OR IDbSet<IUser> OR [IDbSet implementation]?
}
public interface IEntityFactory
{
DbSet<IUser> Users { get; }
DbSet<IAccount> Accounts { get; }
}
从那里,我们就有了一个实现库,我们称其为 "Something.Data.Imp":
internal class User : IUser
{
public int ID { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public IAccount Account { get; set; }
public class Configuration : EntityTypeConfiguration<User>
{
public Configuration() : base()
{
...
}
}
}
internal class Account : IAccount
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DbSet<IUser> Users { get; set; } // OR IDbSet<IUser> OR [IDbSet implementation]?
public class Configuration : EntityTypeConfiguration<Account>
{
public Configuration() : base()
{
...
}
}
}
工厂:
public class ImplEntityFactory : IEntityFactory
{
private ImplEntityFactory(string connectionString)
{
this.dataContext = new MyEfDbContext(connectionString);
}
private MyEfDbContext dataContext;
public static ImplEntityFactory Instance(string connectionString)
{
if(ImplEntityFactory._instance == null)
ImplEntityFactory._instance = new ImplEntityFactory(connectionString);
return ImplEntityFactory._instance;
}
private static ImplEntityFactory _instance;
public DbSet<IUser> Users // OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Users; }
}
public DbSet<IAccount> Accounts // OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Accounts; }
}
}
背景:
public class MyEfDataContext : DbContext
{
public MyEfDataContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer<MyEfDataContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new User.Configuration());
modelBuilder.Configurations.Add(new Account.Configuration());
base.OnModelCreating(modelBuilder);
}
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
}
然后前端程序员将会这样使用它:
public class UsingIt
{
public static void Main(string[] args)
{
IEntityFactory factory = new ImplEntityFactory("SQLConnectionString");
IUser user = factory.Users.Find(5);
IAccount usersAccount = user.Account;
IAccount account = factory.Accounts.Find(3);
Console.Write(account.Users.Count());
}
}
所以这就是全部内容了...我希望在这里有人可以指点我方向,或者帮我找到一个好的论据来反驳开发团队。我看了这个网站上关于EF无法与接口一起使用的一些文章和一个回答,说你不能实现IDbSet
(我觉得很奇怪,如果你不能实现它,为什么会提供它?),但到目前为止都没有结果。
预先感谢您的任何帮助! J
IDbSet
可以在单元测试中进行模拟,但是模拟 EF 是另一个困难的任务。参考链接:https://dev59.com/IWw15IYBdhLWcg3wMY-L。 - Ladislav Mrnka