简体   繁体   English

具有服务层的存储库和UoW模式

[英]Repository and UoW pattern with service layer

I'm using Repository and UoW pattern. 我正在使用Repository和UoW模式。 My services look like this: 我的服务如下所示:

public class MyService : IService
{
    private readonly IUnitOfWork<MyContext> unitOfWork;
    private readonly IMyRepository myRepository;

    public MyService(IUnitOfWork<MyContext> unitOfWork, IMyRepository myRepository)
    {
        this.unitOfWork = unitOfWork;
        this.myRepository = myRepository;
    }

    //Methods...
}

Within services, I need to use other entities (for example to check for rights, etc). 在服务中,我需要使用其他实体(例如,检查权限等)。

Is it recommended to use the relevant repositories in the service or use the services directly? 是否建议使用服务中的相关存储库或直接使用服务?

Also, for each user we have rights (boolean) for each CRUD action. 同样,对于每个用户,我们都具有每个CRUD操作的权限(布尔值)。 These rights are stored in the database. 这些权限存储在数据库中。

Should checking of rights be done at the controller level or at the service level? 应该在控制器级别还是在服务级别进行权限检查?

My golden rule is: 我的黄金法则是:

When you get business logic in your UI create a service, otherwise use the repository directly. 当您在UI中获得业务逻辑时,请创建服务,否则直接使用存储库。

So if you have this code in the UI: 因此,如果您在用户界面中有以下代码:

var user = repos.Get(1);
user.FirstName = txtFirstName.Text;
repos.Save(user);

You are fine in my opinion. 我认为你还好。 But if you instead have something like: 但是,如果您有类似以下内容:

var user = userRepository.Get(1);
var accessChecker = authorizationRepository.GetForUser(id);
if (!accessChecker.MaySendEmail(user))
    throw new SecurityException("You may not send emails");

var emailSender = new EmailSenderService();
emailSender.Send(user, txtDestination.Text, txtMessage.Text);
repos.Save(user);

It's likely that you should use a service instead. 您可能应该改用服务。

Don't use your UoW to just wrap your database context. 不要使用您的UoW来包装数据库上下文。 Since all your repositories are directly dependent of a given context (more or less, ofc), your repositories can be included in the UoW. 由于您的所有存储库都直接依赖于给定的上下文(或多或少,取决于ofc),因此您的存储库可以包含在UoW中。 Something along the lines of: 类似于以下内容:

public interface IUnitOfWork<TContext> : IDisposable { }

public abstract class UnitOfWork<TContext> : IUnitOfWork<TContext> {

    private readonly TContext _context;
    protected TContext Context { get{ return _context; } }

    protected UnitOfWork(TContext context){
        _context = context;
    }
}

public interface IMyDbUnitOfWork : IUnitOfWork<MyContext>{

    public ICarRepository Cars { get; }
    public IOwnerRepository Owners { get; }

}

public class MyDbUnitOfWork : UnitOfWork<MyContext>, IMyDbUnitOfWork{

    public MyDbUnitOfWork():base(new MyContext()){}

    private ICarRepository _cars;
    public ICarRepository Cars { 
        get{
            return _cars ?? (_cars = new CarRepository(Context));
        }
    }

    private ICarRepository _owners;
    public IOwnerRepository Owners { 
        get{
            return _owners ?? (_owners = new OwnerRepository(Context));
        }
    }

}


public class MyService : IService
{
    private readonly IMyDbUnitOfWork _unitOfWork;

    public MyService(IMyDbUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    //Methods...
}

Obviously you can create this more or less generic, but I believe this should be enough to pass my point. 显然,您可以创建这个或多或少的通用类,但是我相信这足以说明我的观点。 As a note, and since I normally use IoC frameworks, my services receive an IUnitOfWorkFactory because of the diferent lifestyles. 需要说明的是,由于我通常使用IoC框架, IUnitOfWorkFactory由于生活方式不同,我的服务会收到IUnitOfWorkFactory

For the permissions question, it really depends how much control you want to have and how user friendly you want your application to be. 对于权限问题,它实际上取决于您希望拥有多少控制权以及您希望应用程序对用户友好的程度。 Normally is a mix of both. 通常是两者兼而有之。 Your application should know if your user has access to the screen but also if you must disable buttons accordingly. 您的应用程序应该知道您的用户是否有权访问屏幕,而且还必须相应地禁用按钮。 Since you also must prevent that, if by any reason, the user can invoke your service method, you can't allow it. 由于您还必须防止这种情况发生,因此,无论出于何种原因,用户都可以调用您的服务方法,因此您将不允许这样做。 To solve this problem I don't filter by CRUD actions but by Service actions instead, intercepting every service invocation, which makes it easy to map my permissions to the user interface since normally is a 1 to 1 relation between button action and service action. 为了解决此问题,我不是按CRUD操作而是按服务操作过滤,而是拦截每个服务调用,这使将权限映射到用户界面变得很容易,因为通常按钮操作和服务操作之间是一对一的关系。

I think using repositories is just fine. 我认为使用存储库就可以了。 I wouldn't invent a service layer for each of the repos. 我不会为每个存储库创建一个服务层。 Repository is used for abstracting the data access and service layer is to encapsulate business logic, however with recent trend , I find this overkill. 存储库用于抽象数据访问,而服务层则用于封装业务逻辑,但是从最近的趋势来看,我发现这种方法已经过时了。 Having service layer is fine if they act as controllers but don't try to map one to one to each entity or repo. 如果服务层充当控制器,但不要尝试将每个实体或存储库一对一映射,则可以使用服务层。

I typically use services from the UI and those services in turn use the repositories. 我通常使用UI中的服务,而这些服务依次使用存储库。 I also find it useful to have some domain objects that encapsulate reusable logic in the services. 我还发现拥有一些域对象来封装服务中的可重用逻辑很有用。

I do this so that rather than services calling each other and getting circular references, services use a common domain object instead. 我这样做是为了使服务使用公共域对象,而不是彼此调用并获取循环引用。 This avoids circular references and people copying and pasting the same code all over the place.This domain object may then use the repositories if necessary. 这样可以避免循环引用,也避免了人们在各处复制和粘贴相同的代码。然后,如有必要,此域对象可以使用存储库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM