如何透明地处理多个存储后端

发布于 2024-10-21 01:22:23 字数 808 浏览 6 评论 0原文

我现在正在使用一个应用程序,该应用程序使用第三方 API 来处理一些与电子邮件相关的批量任务,为了使其正常工作,我们需要在此服务中存储一些信息。不幸的是,这些信息(名字/姓氏、电子邮件地址)也是我们希望在应用程序中使用的信息。我的正常倾向是选择一个规范数据源并坚持使用它,但是每次我想要查找这些字段时都往返到 Web 服务并不是一个真正可行的选择(我们经常使用其中一些字段),并且该服务的 API 要求将记录存储在那里,因此遗憾的是,重复是必要的。

但我没有兴趣在我们的业务类中的每个方法中添加代码,以便在数据更新时将数据同步到 Web 服务,而且我也不认为我的实体应该知道在属性中更新自身的服务设置器(或任何其他正在更新“真相”的东西)。

我们使用 NHibernate 来满足所有 DAL 需求,在我看来,这种数据复制实际上是一个持久性问题 - 因此我使用 EventListener(PostInsert 和 PostUpdate)创建了一个 PoC 实现,用于检查实体是否是输入 X,并且任何字段 [Y..Z] 已更改,使用新状态更新 Web 服务。

我觉得这在确保我们的数据是规范来源和确保它被透明地复制以及最大限度地减少更改被遗漏并让我们陷入不匹配情况的机会之间取得了良好的平衡(而不是结束)例如,如果服务无法访问,我们稍后会进行手动批量更新,但为了一般情况下每个人的理智,我们的目标是我们永远不必考虑它),但我和我的同事仍然有一定程度的了解。对这条前进的道路感到不舒服。

这是一个在不合时宜的时候邀请猛禽进入我的数据库的可怕想法吗?使用 EventListener 是完全合理的吗?对于不太理想的情况,它是否是一个有用的解决方案,我们可以凑合着并永远继续前进?如果我们继续沿着这条路前进,在事件管道中是否有我应该警惕的问题?

I'm working with an application right now that uses a third-party API for handling some batch email-related tasks, and in order for that to work, we need to store some information in this service. Unfortunately, this information (first/last name, email address) is also something we want to use from our application. My normal inclination is to pick one canonical data source and stick with it, but round-tripping to a web service every time I want to look up these fields isn't really a viable option (we use some of them quite a bit), and the service's API requires the records to be stored there, so the duplication is sadly necessary.

But I have no interest in peppering every method throughout our business classes with code to synchronize data to the web service any time they might be updated, and I also don't think my entity should be aware of the service to update itself in a property setter (or whatever else is updating the "truth").

We use NHibernate for all of our DAL needs, and to my mind, this data replication is really a persistence issue - so I've whipped up a PoC implementation using an EventListener (both PostInsert and PostUpdate) that checks, if the entity is of type X, and any of fields [Y..Z] have been changed, update the web service with the new state.

I feel like this is striking a good balance between ensuring that our data is the canonical source and making sure that it gets replicated transparently and minimizing the chances for changes to fall through the cracks and get us into a mismatch situation (not the end of the world if eg. the service is unreachable, we just do a manual batch update later, but for everybody's sanity in the general case, the goal is that we never have to think about it), but my colleagues and I still have a degree of uncomfortableness with this way forward.

Is this a horrid idea that will invite raptors into my database at inopportune times? Is it a totally reasonable thing to do with an EventListener? Is it a serviceable solution to a less-than-ideal situation that we can just make do with and move on forever tainted? If we soldier on down this road, are there any gotchas I should be wary of in the Events pipeline?

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

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

发布评论

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

评论(1

芸娘子的小脾气 2024-10-28 01:22:23

如果数据存储(在您的情况下是 Web 服务)不可靠,我会引入事务(操作)的概念并将它们存储在本地数据库中,然后定期从数据库中提取它们并针对 Web 服务(其他数据存储)执行。

像这样的事情:

    public class OperationContainer
    {
    public Operation Operation; //what ever operations you need CRUD, or some specific
    public object Data; //your entity, business object or whatever
    }

    public class MyMailService
    {
    public SendMail (MailBusinessObject data)
    {
    DataAcceessLair<MailBusinessObject>.Persist(data);
    OperationContainer operation = new OperationContainer(){Operation=insert, Data=data};
    DataAcceessLair<OperationContainer>.Persist(operation);
    }
    }

    public class Updater
    {
    Timer EverySec;
    public void OnEverySec()
    {
    var data = DataAcceessLair<OperationContainer>.GetFirstIn(); //FIFO
    var webServiceData = WebServiceData.Converr(data); // do the logic to prepare data for WebService
try
{
    new WebService().DoSomething(data);
DataAcceessLair<OperationContainer>.Remove(data);
}
    }
    }

这实际上非常接近智能客户端的概念 - 从技术上讲不符合逻辑。看一下书:.NET Domain-Driven Design with C#: Problem-Design-Solution, Chapter 10。或者看一下书中的源代码,它非常接近您的情况:http://dddpds.codeplex.com/

In case of unreliable data stores (web service in your case), I would introduce a concept of transactions (operations) and store them in local database, then periodically pull them from DB and execute against the Web Service (other data store).

Something like this:

    public class OperationContainer
    {
    public Operation Operation; //what ever operations you need CRUD, or some specific
    public object Data; //your entity, business object or whatever
    }

    public class MyMailService
    {
    public SendMail (MailBusinessObject data)
    {
    DataAcceessLair<MailBusinessObject>.Persist(data);
    OperationContainer operation = new OperationContainer(){Operation=insert, Data=data};
    DataAcceessLair<OperationContainer>.Persist(operation);
    }
    }

    public class Updater
    {
    Timer EverySec;
    public void OnEverySec()
    {
    var data = DataAcceessLair<OperationContainer>.GetFirstIn(); //FIFO
    var webServiceData = WebServiceData.Converr(data); // do the logic to prepare data for WebService
try
{
    new WebService().DoSomething(data);
DataAcceessLair<OperationContainer>.Remove(data);
}
    }
    }

This is actually pretty close to the concept of smart client - technically not logicaly. Take a look at book: .NET Domain-Driven Design with C#: Problem-Design-Solution, chapter 10. Or take a look at source code from the book, it's pretty close to your situation: http://dddpds.codeplex.com/

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