【问题标题】:Asp.net MVC Nhibernate : Can not modify more than one base table through a join viewAsp.net MVC Nhibernate:不能通过连接视图修改多个基表
【发布时间】:2016-03-11 20:44:13
【问题描述】:

我正在与NHibernateMySQL 合作开发ASP.Net MVC Web 项目。一切正常,但我在以下流程中随机出现错误。

NHibernate.ISession _Session = MvcApplication.SessionFactory.GetCurrentSession();

using (ITransaction t = _Session.BeginTransaction())
  {
     SavedIDOfModel1 = (Int32)_Session.Save(Model1);
     //DAO will use same _Session to get data from DB
     Model2 oModel2 = DAO.GetModel2FromDB();     
    oModel2.Model1ID = SavedIDOfModel1;
    _Session.SaveOrUpdate(oModel2);
        t.Commit(); 
  }


//DAO will use same _Session to get data from DB

DAO.GetModel3FromDB();
DAO.AddHistoryInDB(); 

AddHistoryInDB 只是创建一个新模型HISTORY 并将其提交到数据库中。模型HISTORY 只需要来自之前的Model1CaseID

在保存HISTORY 时,某些情况下没有保存history。 此函数将使用相同的 _session 和新事务向 DB 发送数据

只是想知道我在历史函数DAO.AddHistoryInDB() 中将数据插入数据库的方法是否正确。 ?

编辑:

以下是例外:

    Unable to add case history.

    MySql.Data.MySqlClient.MySqlException (0x80004005):

 Can not modify more than one base table through a join view 

'easyslotdb.view_appointment' at MySql.Data.MySqlClient.MySqlStream.ReadPacket() at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId) at MySql.Data.MySqlClient.Driver.GetResult(Int32 statementId, Int32& affectedRows, Int64& insertedId) at 

MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force) at MySql.Data.MySqlClient.MySqlDataReader.NextResult() at 

MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior) at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery() at 

NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) at 

NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation) at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)

据我了解,当我们更新数据库视图时会发生这种情况,但在我的情况下我没有更新它。任何人都可以帮忙吗?

【问题讨论】:

    标签: c# mysql asp.net-mvc database nhibernate


    【解决方案1】:

    NHibernate 会话跟踪他们的交易并处理他们的处置,不需要对他们的交易做using。改为“尝试工作提交捕获回滚”。

    SaveOrUpdate 调用是一个错误。 Save 用于持久化一个新实体,Update 用于将来自另一个会话的已经持久化的实体附加到当前会话中,以便最终将其更改应用于以后的Flush。它远不等同于 SQL UPDATE。在从同一会话加载且之前未被驱逐的实体上调用它是无稽之谈。

    在 NHibernate 中没有要求更新 DB 中特定实体的方法(在实体框架中也没有)。有一个全局 Flush 应用 db 中的所有更改(插入/更新/删除;参见 its logic here)。提交事务也会触发刷新。

    所以,删除您的使用,删除对SaveOrUpdate 的调用,提交您的事务或在出现异常时回滚它(并调用throw; 让异常完成其工作)。

    至于你的实际问题,不知道。如果没有AddHistoryInDB 的代码,也没有详细解释你的情况是什么“保存历史”,我很无能为力。

    旁注:

    • 您可以直接在Model1Save 之后读取它,而不是将Save 返回值转换为您的id 类型。
    • 如果您已将Model1 实体属性映射到与Model2 对应的Model1ID,请避免同时使用两者。只要不禁用代理,只需保留实体属性并将您的实体分配给它以进行更改。如果您只有它的 id,_Session.Load<Model1>(id) 会为您提供一个代理,而无需访问数据库。

    解决评论问题:

    第一个Save没有错,我指的是SaveOrUpdate。 (我只是给出了避免 ID 演员的提示,但这个 Save 必须保留。)

    在提交主题上,在将其关联到 Model2 之前,我们不需要确保 Model1 存在。 NHibernate 处理这个问题,它知道如何以正确的顺序将Flush all 放入 DB。你失去了这个Commit的工作单元语义。

    在网络环境中,更常见的做法是让一个事务覆盖所有数据库影响。您可以发出中间刷新(以确保您的视图能够为您提供您想要的数据),但不需要Commit。正如我目前所看到的,您当前的案例应该是一个工作单元。所以它应该在单个事务中。

    关于视图,我猜这是一个数据库视图。在这种情况下,在查询之前发出明确的_Session.Flush() 会更安全。但是如果你测试没有它会发生什么可能会很有趣:当你问他查询你的视图时,NHibernate 可能会自己发出它,这取决于你如何映射它。 (见Flush documentation。)

    【讨论】:

    • 感谢 Frederic 的详细解释。只是几件事: 1. Model1 ID 是在 DB 中自动生成的,这就是我使用 Save 来获取该 ID 的原因。在保存 Model1 后,我需要 Model2 的这个 id。 2. 我使用 transaction.commit() 只是为了确保在触摸 Model2 之前成功提交 Model1,然后我需要一个视图,在使用该视图之前必须提交 Model1。 3. 关于会话...我在开始请求中绑定 NHibernate 会话,然后在 global.asax 中的结束请求事件中解除绑定并处理它。
    • 我已经编辑了我的答案以回复您的评论,并且我在我的第一个答案中也调整了一些点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2020-12-17
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多