使用NHibernate通过Web服务保存数据?

时间:2009-10-26 21:30:44

标签: web-services nhibernate dataset asmx

我们目前有一个应用程序,它通过Web服务从服务器检索数据并填充DataSet。然后,API的用户通过对象操纵它,而对象又改变数据集。然后将更改序列化,压缩并发送回服务器以进行更新。

但是,我已经开始在项目中使用NHibernate,我真的很喜欢POCO对象的断开连接性。我们现在遇到的问题是我们的对象与内部DataSet紧密相关,以至于它们在很多情况下无法使用,我们最终会使重复的POCO对象来回传递。

Batch.GetBatch() -> calls to web server and populates an internal dataset
Batch.SaveBatch() -> send changes to web server from dataset 

有没有办法实现我们使用的类似模型,通过Web服务进行所有数据库访问但使用NHibernate?

修改1

我有一个部分解决方案,它通过Web服务工作并持续存在,但它有两个问题。

  1. 我必须序列化并发送我的整个集合,而不仅仅是更改项目
  2. 如果我在返回我的对象​​时尝试重新填充该集合,那么我丢失的任何引用都会丢失。
  3. 这是我的示例解决方案。

    客户端

    public IList<Job> GetAll()
    {
        return coreWebService
          .GetJobs()
          .BinaryDeserialize<IList<Job>>();
    }
    
    public IList<Job> Save(IList<Job> Jobs)
    {
        return coreWebService
                 .Save(Jobs.BinarySerialize())
                 .BinaryDeserialize<IList<Job>>();
    }
    

    服务器端

    [WebMethod]
    public byte[] GetJobs()
    {
        using (ISession session = NHibernateHelper.OpenSession())
        {
            return (from j in session.Linq<Job>()
                    select j).ToList().BinarySerialize();
        }
    }
    
    [WebMethod]
    public byte[] Save(byte[] JobBytes)
    {
        var Jobs = JobBytes.BinaryDeserialize<IList<Job>>();
    
        using (ISession session = NHibernateHelper.OpenSession())
        using (ITransaction transaction = session.BeginTransaction())
        {
            foreach (var job in Jobs)
            {
                session.SaveOrUpdate(job);
            }
            transaction.Commit();
        }
    
        return Jobs.BinarySerialize();
    }
    

    正如您所看到的,我每次都将整个集合发送到服务器,然后返回整个集合。但是我得到了一个被替换的集合,而不是一个合并/更新的集合。更不用说当只有部分数据可以改变时,来回发送所有数据似乎非常低效。

    修改2

    我在网上看到了几个关于透明持久机制的引用。我不确定这些是否有效,而且大多数都看起来很具实验性。

    我很难找到我们今天使用的DataSet模型的替代品。我想摆脱该模型的原因是因为将每个类的每个属性绑定到数据集的行/单元需要大量的工作。然后它还将我的所有课程紧密地结合在一起。

2 个答案:

答案 0 :(得分:0)

我只是粗略地看一下你的问题,所以如果我的回答是短视的,请原谅我,但这里有:

我认为你不能在逻辑上摆脱从域对象到DTO的映射。

通过线路使用域对象,您将紧密耦合客户端和服务,首先获得服务的部分原因是促进松散耦合。所以这是一个直接的问题。

最重要的是,您将最终得到一个脆弱的域逻辑接口,您无法在不破坏客户端的情况下在服务端进行更改。

我怀疑你最好的选择是实现松散耦合的服务,该服务实现REST /或其他松散耦合的接口。您可以使用诸如automapper之类的产品来简化和简化转换,并在必要时平整数据结构。

此时我不知道有什么方法可以真正减少执行界面层所涉及的冗长程度,但是已经处理过没有付出努力的大型项目我可以诚实地告诉你节省的资金不值得它

答案 1 :(得分:0)

我认为您的问题围绕着这个问题:

http://thatextramile.be/blog/2010/05/why-you-shouldnt-expose-your-entities-through-your-services/

你或者你不打算通过网络发送ORM实体吗?

由于您拥有面向服务的架构。我(就像作者一样)不推荐这种做法。

我使用NHibernate。我称之为ORM实体。它们是POCO模型。但他们有虚拟的&#34;允许延迟加载的属性。

但是,我也有一些DTO-Objects。这些也是POCO。这些没有懒惰的加载友好属性。

所以我做了很多&#34;转换&#34;。我将ORM-Entities(与NHibernate)水合...然后我最终将它们转换为Domain-DTO-Objects。是的,它在开始时很臭。

服务器发出Domain-DTO-Objects。没有延迟加载。我必须用&#34; Goldie Locks&#34;填充它们。 &#34;恰到好处&#34;模型。 Aka,如果我需要有一个级别的孩子的父母,我必须事先了解并通过这种方式发送Domain-DTO-Objects,只需适量的水合作用。

当我发回Domain-DTO-Objects(从客户端到服务器)时,我必须撤消该过程。我将Domain-DTO-Objects转换为ORM-Entities。并允许NHibernate与ORM-Entities一起使用。

因为架构是'#34;断开&#34;,我做了很多(NHiberntae)&#34; .Merge()&#34;调用

        // ormItem is any NHibernate poco
        using (ISession session = ISessionCreator.OpenSession())
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.BeginTransaction();
                ParkingAreaNHEntity mergedItem = session.Merge(ormItem);
                transaction.Commit();
            }
        }

.Merge是一件很棒的事情。实体框架没有它。嘘声。

这有很多设置吗?是。 我认为它是完美的吗?否。

然而。因为我发送的非常基本的DTO(Poco&#39; s)不是&#34;风味&#34;对于ORM,我有能力在不将我的合同交给外界的情况下切换ORM。

我的数据层可以是ADO.NET,EF,NHibernate或其他任何东西。我必须写&#34;转换器&#34;如果我切换,和ORM代码,但其他一切都是孤立的。

很多人和我争辩。他们说我做得太多了,ORM实体也没问题。

同样,我喜欢&#34;现在允许任何延迟加载&#34;出场。而且我更喜欢将数据层隔离开来。我的客户不应该知道或关心我的数据层/选择。

在EF和NHibernate之间存在足够的细微差别(或者一些不那么微妙的差异),以阻止游戏计划。

我的Domain-DTO-Objects看起来像我的ORM实体一样95%?是的。但它的5%可能会让你感到沮丧。

从DataSet迁移,特别是如果它们是从TSQL中的很多商业逻辑的存储过程中填充的,并不是一件轻而易举的事。但是现在我做了对象模型,而且我从不编写一个不是简单的CRUD函数的存储过程,我永远不会回去。

我讨厌存储过程中使用voodoo TSQL的维护项目。它已经不再是1999了。好吧,大多数地方。

祝你好运。

PS没有.Merge(在EF中),这是你在断开连接的世界中必须做的事情:(boo microsoft)

http://www.entityframeworktutorial.net/EntityFramework4.3/update-many-to-many-entity-using-dbcontext.aspx