【问题标题】:EF6 Repository pattern in Windows ServiceWindows 服务中的 EF6 存储库模式
【发布时间】:2017-08-17 11:11:09
【问题描述】:

我已经实现了一个 Windows 服务,它从数据库中获取电子邮件列表,并每 60 秒使用 .net 邮件发送它们。 我是使用存储库模式设计的,请看解决方案文件夹和项目的截图。Click to see the picture

问题:

  1. 就模式而言,我是否走在正确的轨道上?分离项目的结构,为每个存储库创建一个接口,为每个存储库创建一个服务。
  2. 如果某些业务逻辑与数据库无关,我还需要为它们创建一个存储库还是一个服务就足够了?
  3. 我有一个 SMTP 服务类,它正在实现 .net 邮件和发送电子邮件,当我发送每封电子邮件时,我需要更新数据库,我想知道将更新逻辑放在 SMTP 服务类中是否是好的做法?如下所示

        public class SMTPService : ISMTPService
        {
    
            SmtpClient client;
            MailMessage newMessage;
            EmailService emailService;
            IEventLoggerService MailCheckerLog;
    
            public async Task SendEmail(tb_Email email)
            {...}
    
            void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e, tb_Email email)
            {
    
                if (e.Cancelled)
                {
    
                }
                if (e.Error != null)
                {
    
                }
                else
                {
                    email.DateSent = DateTime.Now;
                    emailService.Update(email);
                }
    
                client.Dispose();
                newMessage.Dispose();
    
            }
    

    }

【问题讨论】:

    标签: c# .net entity-framework windows-services console-application


    【解决方案1】:

    我不确定您想要实现的具体目标以及您的业务需求。

    目前该结构还可以,但请考虑一下:您有一个用户实体和一个照片实体。每个用户都必须有一张与之关联的照片。您将如何处理这种情况?

    您必须创建一个 UserRepository 和一个 PhotoRepository。当然,您首先必须插入用户记录,以便照片记录稍后引用它。 因此,您调用 UserRepository 的 Insert() 方法。插入用户时,调用 PhotoRepository 的 Insert() 方法。但是如果 Insert() 失败了怎么办?现在您在数据库中有一个没有照片的用户。

    您必须在一次事务中同时插入用户和照片。这就是工作单元模式的用武之地。如果您的业务逻辑涉及多个实体类型,则必须使用它。如果您所做的只是处理电子邮件,那么这很好。如果没有,您必须将该模式添加到您的应用程序中。查看示例here

    同样,服务是处理业务事务的东西,业务事务可以涉及多种类型的实体。同样,工作单元模式可以帮助您解决这个问题。但通常存储库是根据您的实体创建的,服务是根据您的业务逻辑创建的。在示例中,您可以拥有一个同时使用 UserRepository 和 PhotoRepository(通常通过工作单元)的 UserService。

    如果发送电子邮件,我会再次根据我的业务逻辑设计服务。并且可能业务逻辑是“发送电子邮件”,而不是“通过 SMTP 发送电子邮件”。如果您决定使用像 SendGrid 这样的服务会发生什么?那么它就不再是 SMTPService 了。

    我可能会创建一个 EmailService(你也有),它会有一个 SendEmails() 方法。这将使用 EmailRepository 来获取电子邮件,使用 SMTP 发送,然后更新并通过工作单元保存。

    或者,如果您想真正抽象,您可以使用一种方法创建一个 IEmailSenderService 接口,SendEmail(电子邮件电子邮件)。然后你可以创建一个 SmtpEmailSenderService,它实现了这个接口并包装了 SmtpClient 类并使用 SMTP 发送电子邮件。如果您决定迁移到 SendGrid,您可以创建一个 SendGridEmailSenderService,它使用 HttpClient 向 SendGrid 发出请求。更新仍然是使用存储库和工作单元在 EmailService 中完成的,但是现在 EmailService 本身不使用 SmtpClient,而只是使用 IEmailSenderService 接口。

    【讨论】:

    • 感谢您的回复,我只有一个实体,即电子邮件。我还需要UOW吗?我听说当我们拥有多个实体时这很有用。
    • 如果你只有一个实体,那么你就不需要 uow。
    • 出于好奇,目前我正在使用 SendMailAsync 发送电子邮件并在触发 SendComplete 事件时处理数据库更新。由于我在一批中发送超过 100 封电子邮件,因此有时在处理下一封电子邮件之前不会触发 SendComplete,因此我通过将我的更新方法包装在 dbcontext 的 using 语句中来为每个事务使用新的 dbco0ntext,如下使用 (BBEntities db = new BBEntities()) { db.Entry(obj).State = EntityState.Modified; db.SaveChanges(); }
    • 你将如何通过 UoW 实现这一目标?
    • 同理。 uow 基本上是上下文的包装器。您无需创建和处置上下文,而是创建和处置 uow。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-03
    • 2017-09-19
    • 2016-06-18
    相关资源
    最近更新 更多