webForumDet fria alternativet

NHibernate sparar fel objekt till databasen

.NET

7 svar · 443 visningar · startad av doggelito

Medlem sedan juni 20003 076 inlägg
Frågan#1

Ett skumt fel har uppstått!
Map fil:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
	<class name="Entities.Log, Entities" table="Logs">
		<id name="Id" column="LogID" type="int" unsaved-value="0">
			<generator class="identity" />
		</id>
		<property name="Category" column="Category" type="String" />
		<property name="Source" column="Source" type="String"/>
		<property name="Description" column="Description" type="String"/>
		<property name="User" column="[User]" type="String"/>
		<property name="Ip" column="Ip" type="String"/>
		<property name="CreateDate" column="CreateDate" type="DateTime" />
		<property name="SiteName" column="SiteName" type="String"/>
	</class>
</hibernate-mapping>

Sparar objekt:

Entities.Log log = new Entities.Log();
log.Category = "LOGIN";
log.Source = "";
log.Description = "Loggade in";
log.SiteName = site.Name;
log.User = user.Profile.FirstName + " " + user.Profile.LastName;
log.Ip = Request.UserHostAddress;
log.CreateDate = DateTime.Now;
LogDao.Save(log);

Denna kod funkar "typ" som den ska, objektet log sparas som den ska till databasen.
Men:
I samma skede som loggen sparas så spar NHibernate även objektet Site!
Hur kan det komma sig när log inte har någon relation alls till site?

Medlem sedan aug. 20003 575 inlägg
#2

Vad händer i LogDao.Save()?

Kan det vara så att ett anrop till session.Flush() utförs?

Medlem sedan juni 20003 076 inlägg
#3

Saven ser ut så här:

        public dbReturnValues Save(T objectToSave)
        {
            dbReturnValues retVal = new dbReturnValues();
            ITransaction tx = null;

            try
            {
                tx = NHibernateHelper.GetCurrentSession().BeginTransaction();
                NHibernateHelper.GetCurrentSession().Save(objectToSave);

                tx.Commit();
                retVal.Success = true;
            }
            catch (Exception ex)
            {
                if (tx != null)
                    tx.Rollback();
                
                throw new Exception(ex.Message);
            }
            finally
            {
                tx.Dispose();
            }

            return retVal;
        }

Jag har inte specat en Flush någon annanstans i koden heller.
Gör NHibernate en intern Flush automatiskt när den stängs eller vid annat tillfälle?

Medlem sedan aug. 20003 575 inlägg
#4

Vad jag förstår av dokumentationen så körs en Flush vid transaction.Commit().

Lite off-topic, du bör se över din felhantering.

            try
            {
                tx = NHibernateHelper.GetCurrentSession().BeginTransaction();
                NHibernateHelper.GetCurrentSession().Save(objectToSave);

                tx.Commit();
                retVal.Success = true;
            }
            catch (Exception ex)
            {
                if (tx != null)
                    tx.Rollback();
                
                throw new Exception(ex.Message);
            }

Kör en rethrow istället för att skapa en ny instans av exception.

skriv enbart throw;

            try
            {
                tx = NHibernateHelper.GetCurrentSession().BeginTransaction();
                NHibernateHelper.GetCurrentSession().Save(objectToSave);

                tx.Commit();
                retVal.Success = true;
            }
            catch (Exception)
            {
                if (tx != null)
                    tx.Rollback();
                
                throw;
            }
Medlem sedan juni 20003 076 inlägg
#5

Ahh, så klart. Tack för tipset! :)

Jag hittade på stycket om Flush och det är som du skriver, vid transaction.Commit() som den flushar.
Det finns dock FlushMode att ställa in, frågan är om man vågar sätta den till Never? Vilka konsekvenser kan det få?

NHibernate hjälpfil skrev:

It is possible to change the default behavior so that flush occurs less frequently. The FlushMode class defines three different modes: only flush at commit time (and only when the NHibernate ITransaction API is used), flush automatically using the explained routine, or never flush unless Flush() is called explicitly. The last mode is useful for long running units of work, where an ISession is kept open and disconnected for a long time

Medlem sedan juni 20008 205 inlägg
#6

Nickemannen skrev:

Kör en rethrow istället för att skapa en ny instans av exception.

skriv enbart throw;

Just i det här fallet är det ännu enklare eftersom transaktioner är disposable:

            using (var tx = NHibernateHelper.GetCurrentSession().BeginTransaction();)
            {
                NHibernateHelper.GetCurrentSession().Save(objectToSave);
                tx.Commit();
                retVal.Success = true;
            }

Och flukta in http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/manipulatingdata.html#manipulatingdata-exceptions

Medlem sedan juni 20003 076 inlägg
#7

Har jag fattat rätt om att jag kan skriva så här då?

public dbReturnValues Save(T objectToSave)
        {
            dbReturnValues retVal = new dbReturnValues();
            using (var tx = NHibernateHelper.GetCurrentSession().BeginTransaction())
            {
                NHibernateHelper.GetCurrentSession().Save(objectToSave);
                tx.Commit();
                retVal.Success = true;
            }
            return retVal;
        }

Alltså helt utan try,catch?

Medlem sedan juni 20008 205 inlägg
#8

Ja, det blir ekvivalent med:

public dbReturnValues Save(T objectToSave)
{
	dbReturnValues retVal = new dbReturnValues();
	var tx = NHibernateHelper.GetCurrentSession().BeginTransaction();
	try
	{
		NHibernateHelper.GetCurrentSession().Save(objectToSave);
		tx.Commit();
		retVal.Success = true;
	}
	finally
	{
		tx.Dispose();
	}
	return retVal;
}
263 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
124 ms — deklarationer (db)
0 ms — hämta statistik (cache)
133 ms — hämta tråd, inlägg och bilagor (db)
126 ms — ändringar (db)