具有存储库模式且没有数据库的EntityFramework

时间:2013-12-23 18:45:26

标签: entity-framework asp.net-web-api repository-pattern

我有一个我在N-Tier系统上构建的web api项目。在不对整个系统进行太多更改的情况下,我将不会触及有权访问数据库的数据服务器。相反,我正在使用.NET远程处理创建一个tcp通道,允许我向数据服务器发送请求,然后数据服务器将查询数据库并发回一个响应对象。

在我的应用程序中,我想使用实体框架来创建我的datacontexts(工作单元),然后创建一个与这些上下文接口的存储库模式,这些模式将由我创建的web api项目调用。

但是,我遇到了实体框架的问题,因为它要求我与数据库建立连接。无论如何,我可以创建一个完整的实体框架项目,没有任何sql连接到数据库?我只需要dbcontexts,我将映射我的响应对象,我认为EF会做我需要的(即帮助设计,团队合作,并提供一个漂亮的图形设计师);但它会抛出一个错误,坚持我需要一个连接字符串。

我一直在寻找不需要数据库的教程,也没有任何sql连接字符串(这也就是没有localdb)。

1 个答案:

答案 0 :(得分:0)

好的,按照承诺,我有3个解决方案。我亲自去了#3。

注意:只要存在存储库模式,并且" datacontext"使用时,这被解释为您的UnitOfWork。

解决方案1:创建单例以表示您的datacontext。

http://www.breezejs.com/samples/nodb

我在访问BreezeJS.com的网站后找到了这个想法并检查了他们的样本。他们有一个名为NoDb的样本,它允许他们创建一个单例,它可以创建一个项目和一个项目列表,以及一个填充datacontext的方法。您可以创建单个内容来锁定内存中的空间以防止任何类型的线程冲突。这是代码的一小部分:

//generates singleton
public class TodoContext
{
    static TodoContext{ }
    private TodoContext() { }

    public static TodoContext Instance
    {
        get
        {
            if (!__instance._initialized)
            {
                __instance.PopulateWithSampleData();
                __instance._initialized = true;
            }
            return __instance;
        }
    }

    public void PopulateWithSampleData()
    {
        var newList = new TodoItem { Title = "Before work"};
        AddTodoList(newList);
        var listId = newList.TodoListId;
        var newItem = new TodoItem { 
               TodoListId = listId, Title = "Make coffee", IsDone = false };
        AddTodoItem(newItem);
        newItem = new TodoItem { 
               TodoListId = listId, Title = "Turn heater off", IsDone = false };
        AddTodoItem(newItem);
    }

   //SaveChanges(), SaveTodoList(), AddTodoItem, etc.
   { ... }

   private static readonly Object __lock = new Object();
   private static readonly TodoContext __instance = new TodoContext();
   private bool _initialized;
   private readonly List<TodoItem> _todoLists = new List<TodoItem>();
   private readonly List<KeyMapping> _keyMappings = new List<KeyMapping>();

 }

包含一个存储库,它指导如何保存上下文以及在保存上下文之前需要完成的操作。它还允许项目列表可查询。

我遇到的问题: 我觉得在创建新的datacontexts时有更高的维护。如果我有StateContext,CityContext,CountryContext,那么创建它们的开销就太大了。我试图绕过彼此将它们彼此联系起来时遇到了问题。另外,我不太确定有多少人同意使用单身人士。我已经阅读过文章,我们应该不惜一切代价避免单身人士。对于那些阅读这么多代码的人,我更担心。

解决方案2:覆盖DropCreateDatabaseAlways的种子() http://www.itorian.com/2012/10/entity-frameworks-database-seed-method.html

对于这个技巧,你必须创建一个名为SampleDatastoreInitializer的类,它继承自System.Data.Entity.DropCreateDatabaseAlways,其中T是datacontext,它引用了POCO模型的集合。

public class State
{
    [Key()]
    public string Abbr{ get; set; }
    public string Name{ get; set; }
}

public class StateContext : DbContext
{
    public virtual IDbSet<State> States { get; set; }
}

public class SampleDatastoreInitializer : DropCreateDatabaseAlways<StateContext>
{
    protected override void Seed (StateContext context)
    {
        var states = new List<State>
        {
            new State { Abbr = "NY", Name = "New York" },
            new State { Abbr = "CA", Name = "California" },
            new State { Abbr = "AL", Name = "Alabama" },
            new State { Abbr = "Tx", Name = "Texas" },
        };
        states.ForEach(s => context.States.Add(s));
        context.SaveChanges();
    }
}

这实际上将数据嵌入到缓存中,DropCreateDatabaseAlways意味着它将删除缓存并重新创建它,无论如何。如果您使用IDatabaseInitializer的其他方法,并且您的模型具有唯一键,则可能会出现异常错误,在第一次运行它时,它可以正常运行,但是一次又一次地运行它会因为您的原因而失败。重新违反主键的限制(因为你要添加重复的行)。

我遇到的问题: 这似乎只应用于在您测试应用程序时提供样本数据,而不是用于生产级别。此外,我必须不断为每个上下文创建一个新的初始化程序,这会在可维护性解决方案1中发现类似的问题。这里没有自动发生的事情。但是如果你想要一种方法来注入示例代码而不需要连接到数据库,这是一个很好的解决方案。

解决方案3:具有存储库的实体框架(内存持久性)

我从这个网站得到了这个解决方案: http://www.roelvanlisdonk.nl/?p=2827

他首先使用EF5和EF5 dbcontexts的代码生成器模板设置edmx文件,您可以从VS扩展库获取。

他首先使用edmx创建上下文并更改tt模板以绑定到他所创建的存储库类,以便存储库跟踪datacontext,并提供通过存储库查询和访问数据的选项;虽然他将存储库称为MemoryPersistenceDbSet,但在他的网站中。

他修改的模板将用于创建将绑定到所有人共享的接口(IEntity)的datacontexts。这样做是很好的,因为你正在建立一个依赖注入,这样你就可以通过T4模板添加你想要的任何实体,并且没有抱怨。

此解决方案的优点: 在存储库模式中包装edmx允许您利用n层体系结构,以便对后端所做的任何更改都不会影响前端,并允许您分离前端和后端之间的接口,以便没有耦合依赖。所以也许以后,我可以用petapoco,大量或其他ORM替换我的edmx,或者从内存持久性切换到从数据库中获取数据。

我按照解释完全遵循了一切。我做了一个修改:

在.Context.tt的t4模板中,添加了DbSetInConstructor,我的代码编写如下:

public string DbSetInConstructor(EntitySet entitySet)
{
    return string.Format(
        CultureInfo.InvariantCulture,
        “this.{1} = new BaseRepository();”,
        _typeMapper.GetTypeName(entitySet.ElementType), entitySet);
}

因为在我的情况下,我有entityset = Persons和entityname = Person。所以会有差异。但这应涵盖所有基础。

最后一步:

因此,您是否选择了解决方案1,2或3.您有一种方法可以自动填充您的应用程序。在这些情况下,存根嵌入在代码中。就我而言,我所做的就是拥有我的网络服务器(包含我的前端应用程序),联系我的数据服务器,让数据服务器查询数据库。数据服务器将接收数据集,对其进行序列化,然后将其传递回Web服务器。 Web服务器将获取该数据集,对其进行反序列化,并自动映射到对象集合(列表,可枚举或对象集合等)。

我会更充分地发布解决方案,但这三种解决方案之间的细节太多了。希望这些解决方案能够指出任何人都朝着正确的方向前进。

依赖注入 如果有人想要了解如何允许DI到api控制器的一些信息,Peter Provost提供了一个非常有用的博客,解释了如何做到这一点。他做得非常好。

http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/

包装edmx的存储库的更多有用链接: http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx http://www.codeproject.com/Articles/688929/Repository-Pattern-and-Unit-of