包装DbSet< TEntity>使用自定义DbSet / IDbSet? [英] Wrapping DbSet<TEntity> with a custom DbSet/IDbSet?

查看:1640
本文介绍了包装DbSet< TEntity>使用自定义DbSet / IDbSet?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我觉得这是有点可笑的事,但我的团队的其他成员坚持要求它,我不能拿出反对它一个很好的理由不是我认为这是愚蠢的其他...

First off, I think this is somewhat ridiculous to do but the other members of my team insist upon it and I can't come up with a good argument against it other than "I think it's dumb"...

我们现在要做的是创建一个完全抽象的数据层,然后有一个数据层的各种实现。够简单了吧?进入实体框架4.1 ...

What we're trying to do is create a completely abstract data layer and then have various implementations of that data layer. Simple enough, right? Enter Entity Framework 4.1...

我们的这里的最终目标是,程序员(我尽我所能留只在数据层)永远希望有暴露在具体的类。他们永远只能希望在他们的code使用的接口,除了需要明显的实例工厂。

Our end goal here is that the programmers (I do my best to stay only on the data layer) never want to have to be exposed to the concrete classes. They only ever want to have to use interfaces in their code, aside from obviously needing to instantiate the factory.

我要实现类似如下:

首先,我们有所有的接口我们的共同库中,我们把它叫做Common.Data

First we have our "Common" library of all of the interfaces, we'll call it "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

From that we then have an implementation library, we'll call it "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; }
}

然后,前端程序员会使用它,例如:

Then the front-end programmers would be using it such as:

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());
    }
}

这就是pretty多少呢......我希望有人就在这里也许能够要么点我在正确的方向,或帮助我,我可以在开发团队还击一个很好的理由。我看了这个网站关于EF不能够与接口和一条回复工作的一些其他物品说,你不能执行 IDbSet (我觉得有些好奇,为什么他们会提供,如果你无法实现它?),但迄今没有结果。

So that's pretty much it... I'm hoping someone on here might be able to either point me in the right direction or help me out with a good argument that I can fire back at the development team. I've looked at some other articles on this site about EF not being able to work with interfaces and one reply saying that you can't implement IDbSet (which I find kind of curious, why would they provide it if you couldn't implement it?) but so far to no avail.

在此先感谢您的帮助!
Ĵ

Thanks in advance for any help! J

推荐答案

第一个参数是EF不与接口工作。 DbSet 必须有一个真正的实体,实现定义。

The first argument is that EF doesn't work with interfaces. DbSet must be defined with a real entity implementation.

第二个参数是你的实体不应包含 DbSet - 这是上下文相关的类别以及您的实体应该是纯如的依赖,除非你要执行活动记录模式。即使在这种情况下,你绝对不会有其他实体不同实体的访问 DbSet 。即使你包装设置你还是太接近EF和实体从来没有财产访问另一个实体类型的所有实体(不仅是关系到当前实例)。

The second argument is that your entities should not contain DbSet - that is context related class and your entities should be pure of such dependency unless you are going to implement Active record pattern. Even in such case you will definitely not have access to DbSet of different entity in another entity. Even if you wrap set you are still too close to EF and entity never have property accessing all entities of another entity type (not only those related to current instance).

只是要清楚 DbSet 在EF具有非常特殊的意义 - 它不是一个集合。这是入口点数据库(例如在 DbSet 每个LINQ查询数据库命中),它是在不暴露在实体上正常的情况。

Just to make it clear DbSet in EF has very special meaning - it is not a collection. It is entry point to database (for example each LINQ query on DbSet hits database) and it is in normal scenarios not exposed on entities.

第三个参数是您使用每个应用程序的单一环境 - 你必须每单厂单私有实例。除非你正在做一些单次运行批处理应用程序<一href=\"http://stackoverflow.com/questions/3653009/entity-framework-and-connection-pooling/3653392#3653392\">it肯定是不对的。

The third argument is that you are using a single context per application - you have a single private instance per singleton factory. Unless you are doing some single run batch application it is definitely wrong.

最后一个参数是简单实用。您将获得不提供的功能浪费时间的抽象不给你(和你的客户)的业务价值。这是不是证明为什么你不应该创建这个抽象。它是关于证明为什么你应该这样做。你会使用它得到了什么价值?如果您的同事是不是能来与具有商业价值可以简单地去你的产品经理,让他用他的力量的论点 - 他认为预算

The last argument is simply practical. You are paid for delivering features not for wasting time on abstraction which doesn't give you (and your customer) any business value. It is not about proving why you should not create this abstraction. It is about proving why you should do it. What value will you get from using it? If your colleagues are not able to come with arguments which have business value you can simply go to your product manager and let him use his power - he holds the budget.

一般的抽象是设计良好的面向对象的应用程序的一部分 - 这是正确的。但是:

Generally abstraction is part of well designed object oriented application - that is correct. BUT:


  • 每个抽象将使您的应用程序以某种方式更为复杂,它会增加开发成本和时间

  • 并非每一个抽象将使您的应用程序更好,更易于维护的 - 太多的抽象具有相反的效果

  • 抽象EF是很难的。说你会在这样抽象的数据访问,您可以用其他实现来替代它对于数据访问大师的任务。首先你必须有很多的数据访问技术很好的经验,能够来定义这种抽象,将与所有这些工作(并最终你只能告诉你的抽象作品与你想过当你设计一个技术)。您将抽象的,因为它不是一个抽象与EF的DbContext API,并没有别的才能正常工作。如果你想建立通用的抽象,你应该开始学习Repository模式,工作模式和规范模式的单位 - 但这是工作的一个大问题,使它们并加以贯彻落实普遍。所需的第一步是隐藏与该后面的抽象数据访问的一切 - 包括LINQ

  • 抽象的数据访问,支持多种API使得只有当你现在就需要它的意义。如果你只是觉得比在业务驱动的项目,谁与想法来到完全错误的决定,开发商是没有能力做的业务布控它可以在将来有用。

在有意义做大量的抽象?

When it make sense to do "a lot of" abstraction?


  • 您现在有这样的要求 - 即移动这样的决定的负担,负责预算/项目范围/需求等人

  • 您需要现在的抽象,简化设计和解决一些问题

  • 您在做开源或业余爱好项目,你是不是由业务需求驱动的,但你的项目的纯度和质量

  • 您正在对平台(长住的零售产品,这将住了很长一段时间)或公共框架 - 这通常返回到第一点,因为这类产品通常有这样的抽象,要求

如果您正在只管应用(按需或外包解决方案大多是单一用途的应用程序)的抽象应该只在必要时使用。这些应用由成本驱动 - 目标是提供有效的解决方案为最小的成本并在最短的时间。这个目标必须实现,即使生成的应用程序将不会太好内部 - 这唯一重要的是,如果申请符合要求。基于任何抽象的如果......会发生或也许我们需要......,其中将在99%从未发生过,而且在大多数情况下,客户最初的合同不算数虚拟(不存在的)的要求增加了成本此种额外的费用。

If you are working only targeted application (mostly single purpose applications on demand or outsourced solutions) the abstraction should be used only if necessary. These applications are driven by costs - the target is delivering working solution for minimal costs and in the shortest time. This target must be achieved even if resulting application will not be very good internally - the only thing which matters is if application meets requirements. Any abstraction based on "what if ... happens" or "perhaps we will need ..." increases costs by virtual (non existing) requirements which will in 99% never happen and in most cases initial contract with customer didn't count which such additional costs.

顺便说一句。这种类型的应用程序是由MS API和设计师的战略目标 - MS会让很多设计师和code发电机,这将创造可以通过人的小技能来制作,而且很便宜的非最优的,但廉价和快速的解决方案。最后一个例子是LightSwitch的。

Btw. this type of applications is targeted by MS APIs and designer strategy - MS will make a lot of designers and code generators which will create non optimal but cheap and quick solutions which can be created by people with smaller skill set and are very cheap. The last example is LightSwitch.

这篇关于包装DbSet&LT; TEntity&GT;使用自定义DbSet / IDbSet?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆