使用存储库和实体框架在领域事件中实现实体持久化?

发布于 2024-11-06 13:08:16 字数 1586 浏览 7 评论 0原文

我正在深入研究领域事件,并且需要一些关于出于历史原因对实体进行持久更新的建议。我的示例涉及用户实体和登录:

    public class UserService
    {
        private UserRepository _repository;

        public UserService()
        {
            _repository = new UserRepository();
        }

        public User SignIn(string username, string password)
        {
            var user = _repository.FindByUsernameAndPassword(username, password);
            //As long as the found object is valid and an exception has not been thrown we can raise the event.
            user.LastLoginDate = DateTime.Now;
            user.SignIn();
            return user;
        }
    }

    public class User
    {
        public User(IEntityContract entityContract)
        {
            if (!entityContract.IsValid)
            {
                throw new EntityContractException;
            }
        }

        public Guid Id { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public DateTime LastLoginDate { get; set; }

        public void SignIn()
        {
            DomainEvent.Raise(new UserSignInEvent() {User = this});
        }
    }

    public class UserSignInEvent : IDomainEvent
    {
        public User User { get; set; }
    }


    public class UserSignInHandler : Handles<UserSignInEvent>
    {
        public void Handle(UserSignInEvent arguments)
        {
            //do the stuff
        }
    }

因此,在我需要做这些事情的地方,我想更新用户对象 LastLoginDate 并可能记录用户由于历史原因登录的日期和时间。 我的问题是,我是否会创建存储库和上下文的新实例来保存处理程序中的更改或将某些内容传递到事件中?这就是我现在正在努力解决的问题。

I am delving into domain events and need some advice about persisting updates to an entity for history reasons. My example deals with a User entity and Signing In:

    public class UserService
    {
        private UserRepository _repository;

        public UserService()
        {
            _repository = new UserRepository();
        }

        public User SignIn(string username, string password)
        {
            var user = _repository.FindByUsernameAndPassword(username, password);
            //As long as the found object is valid and an exception has not been thrown we can raise the event.
            user.LastLoginDate = DateTime.Now;
            user.SignIn();
            return user;
        }
    }

    public class User
    {
        public User(IEntityContract entityContract)
        {
            if (!entityContract.IsValid)
            {
                throw new EntityContractException;
            }
        }

        public Guid Id { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public DateTime LastLoginDate { get; set; }

        public void SignIn()
        {
            DomainEvent.Raise(new UserSignInEvent() {User = this});
        }
    }

    public class UserSignInEvent : IDomainEvent
    {
        public User User { get; set; }
    }


    public class UserSignInHandler : Handles<UserSignInEvent>
    {
        public void Handle(UserSignInEvent arguments)
        {
            //do the stuff
        }
    }

So where I have the do the stuff, I want to update the User object LastLoginDate and possibly log the date and time the user logged in for historical reasons.
My question is, would I create a new instance of my repository and context to save the changes in the handler or pass something into the Event? This is what I am struggling with right now.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

深白境迁sunset 2024-11-13 13:08:16

因此,在我需要做这些事情的地方,我想更新 User 对象 LastLoginDate 并可能记录用户由于历史原因登录的日期和时间。

记住上次登录日期应该是用户自己关心的问题。
您已经有了很好的扩展点 - 用户有登录方法。

我的问题是,我是否会创建存储库和上下文的新实例来保存处理程序中的更改或将某些内容传递到事件中?

用户不应该了解有关实体框架的任何信息。
因此 - User.Events 也不应该知道任何事情。
事件处理程序也不应该知道。

那些位于“外部”(例如应用程序层)的处理程序是允许的。
但如果有必要,他们会从其他地方而不是从用户或事件中找出实体框架上下文。


正如我所见 - 这里的事件仅对于日志记录功能是必需的。

我会写这样的东西:

public class LoginService{
   private Users _users;
   public LoginService(Users users){
     _users = users;
   }         
   public User SignIn(string username, string password){
     var user = _users.ByUsernameAndPassword(username, password);
     user.SignIn();
     return user;
   }
 }

public class User{
   public DateTime LastLoginDate { get; set; }      
   public void SignIn(){
     LastLoginDate = DateTime.Now;
     Raise(new SignedIn(this));
   }
   public class SignedIn:DomainEvent<User>{
     public SignedIn(User user):base(user){}
   }
}

//outside of domain model
public class OnUserSignedIn:IEventHandler<User.SignedIn>{
  public void Handle(User.SignedIn e){
    var u=e.Source;
    var message="User {0} {1} logged in on {1}"
      .With(u.Name,u.LastName,u.LastLoginDate);
    Console.WriteLine(message);
  }
}

这段代码的坏处是服务方法是命令和查询同时进行
(它修改状态并返回结果)。

我将通过引入 来解决这个问题UserContext 将通知用户已登录。

这将不需要返回已登录的用户,
服务当前用户的责任将转移到 UserContext。

关于存储库和更新您的用户 - 我非常确定实体框架足够智能,可以知道如何跟踪实体状态更改。至少在 NHibernate 中 - 我唯一要做的就是在 httprequest 完成时刷新更改。

So where I have the do the stuff, I want to update the User object LastLoginDate and possibly log the date and time the user logged in for historical reasons.

Remembering last login date should be concern of user itself.
You already have nice extension point - user has signIn method.

My question is, would I create a new instance of my repository and context to save the changes in the handler or pass something into the Event?

User shouldn't know anything about entity framework.
Therefore - User.Events shouldn't know anything either.
Domain event handlers shouldn't know too.

Those handlers that live "outside" (e.g. in application layer) are allowed to.
But they would figure out entity framework context from elsewhere and not from user or events if necessary.


As I see it - events here are necessary for logging functionality only.

I would write something like this:

public class LoginService{
   private Users _users;
   public LoginService(Users users){
     _users = users;
   }         
   public User SignIn(string username, string password){
     var user = _users.ByUsernameAndPassword(username, password);
     user.SignIn();
     return user;
   }
 }

public class User{
   public DateTime LastLoginDate { get; set; }      
   public void SignIn(){
     LastLoginDate = DateTime.Now;
     Raise(new SignedIn(this));
   }
   public class SignedIn:DomainEvent<User>{
     public SignedIn(User user):base(user){}
   }
}

//outside of domain model
public class OnUserSignedIn:IEventHandler<User.SignedIn>{
  public void Handle(User.SignedIn e){
    var u=e.Source;
    var message="User {0} {1} logged in on {1}"
      .With(u.Name,u.LastName,u.LastLoginDate);
    Console.WriteLine(message);
  }
}

Bad thing about this code is that service method is command and query simultaneously
(it modifies state and returns result).

I would resolve that with introducing UserContext which would be notified that user has signed in.

That would make need for returning signed in user unnecessary,
responsibility of serving current user would be shifted to UserContext.

About repository and updating Your user - I'm pretty sure entity framework is smart enough to know how to track entity state changes. At least in NHibernate - only thing I'm doing is flushing changes when httprequest finishes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文