/// <summary> /// Load an instance by a unique key that is not the primary key. /// </summary> /// <param name="entityName">The name of the entity to load </param> /// <param name="uniqueKeyPropertyName">The name of the property defining the unique key. </param> /// <param name="key">The unique key property value. </param> /// <param name="session">The originating session. </param> /// <returns> The loaded entity </returns> public object LoadByUniqueKey(string entityName, string uniqueKeyPropertyName, object key, ISessionImplementor session) { ISessionFactoryImplementor factory = session.Factory; IUniqueKeyLoadable persister = (IUniqueKeyLoadable)factory.GetEntityPersister(entityName); //TODO: implement caching?! proxies?! EntityUniqueKey euk = new EntityUniqueKey(entityName, uniqueKeyPropertyName, key, GetIdentifierOrUniqueKeyType(factory), session.EntityMode, session.Factory); IPersistenceContext persistenceContext = session.PersistenceContext; try { object result = persistenceContext.GetEntity(euk); if (result == null) { result = persister.LoadByUniqueKey(uniqueKeyPropertyName, key, session); } return(result == null ? null : persistenceContext.ProxyFor(result)); } catch (HibernateException) { // Do not call Convert on HibernateExceptions throw; } catch (Exception sqle) { throw ADOExceptionHelper.Convert(factory.SQLExceptionConverter, sqle, "Error performing LoadByUniqueKey"); } }
public async Task AlteredBankShouldBeJoinFetchedAsync() { using (var s1 = OpenSession()) { using (var tx = s1.BeginTransaction()) { // Put them all in s1 cache. await(s1.CreateQuery("from Bank").ListAsync()); await(tx.CommitAsync()); } string oldCode; const string newCode = "12345"; // Alter the bank code with another session. using (var s2 = OpenSession()) using (var tx2 = s2.BeginTransaction()) { var accounts = await(s2.Query <Account>().ToListAsync()); foreach (var account in accounts) { account.Bank = null; } await(s2.FlushAsync()); var bank = await(s2.Query <Bank>().SingleAsync()); oldCode = bank.Code; bank.Code = newCode; await(s2.FlushAsync()); foreach (var account in accounts) { account.Bank = bank; } await(tx2.CommitAsync()); } // Check querying them with s1 is still consistent using (var tx = s1.BeginTransaction()) { var accounts = await(s1.CreateQuery("from Account a left join fetch a.Bank").ListAsync <Account>()); var associatedBanks = accounts.Select(x => x.Bank).ToList(); Assert.That(associatedBanks, Has.All.Not.Null, "One bank or more failed loading."); Assert.That(associatedBanks, Has.All.Matches <object>(NHibernateUtil.IsInitialized), "One bank or more was lazily loaded."); Assert.That(associatedBanks, Has.All.Property(nameof(Bank.Code)).EqualTo(oldCode), "One bank or more has no more the old code."); await(tx.CommitAsync()); // Do not check statements count: we are in a special case defeating the eager fetching, because // we have stale data in session for the bank code. // But check that the new code, supposed to be unknown for the session, is not cached. var persister = Sfi.GetEntityPersister(typeof(Bank).FullName); var index = ((IUniqueKeyLoadable)persister).GetPropertyIndex(nameof(Bank.Code)); var type = persister.PropertyTypes[index]; var euk = new EntityUniqueKey(persister.EntityName, nameof(Bank.Code), newCode, type, Sfi); Assert.That(s1.GetSessionImplementation().PersistenceContext.GetEntity(euk), Is.Null, "Found a bank associated to the new code in s1"); } } }
public void Add(ISitecoreDomainEntity entity) { var key = new EntityUniqueKey(entity.Id, entity.GetType()); if (!m_innerCache.ContainsKey(key)) { m_innerCache.Add(key, entity); } }
/// <summary> /// Load an instance by a unique key that is not the primary key. /// </summary> /// <param name="entityName">The name of the entity to load </param> /// <param name="uniqueKeyPropertyName">The name of the property defining the unique key. </param> /// <param name="key">The unique key property value. </param> /// <param name="session">The originating session. </param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> /// <returns> The loaded entity </returns> public async Task <object> LoadByUniqueKeyAsync(string entityName, string uniqueKeyPropertyName, object key, ISessionImplementor session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ISessionFactoryImplementor factory = session.Factory; IUniqueKeyLoadable persister = (IUniqueKeyLoadable)factory.GetEntityPersister(entityName); //TODO: implement caching?! proxies?! var keyType = GetIdentifierOrUniqueKeyType(factory) // EntityUniqueKey was doing this on the type. I suspect this was needed only for its usage in Loader, // which can work with entities as keys not yet instanciated and just represented by their identifiers. // But since removing this call from EntityUniqueKey is done for a patch and that the code path here has // no known bugs with this GetSemiResolvedType, moving its call here for avoiding altering this code // path. See GH1645. .GetSemiResolvedType(factory); EntityUniqueKey euk = new EntityUniqueKey( entityName, uniqueKeyPropertyName, key, keyType, session.Factory); IPersistenceContext persistenceContext = session.PersistenceContext; try { object result = persistenceContext.GetEntity(euk); if (result == null) { result = await(persister.LoadByUniqueKeyAsync(uniqueKeyPropertyName, key, session, cancellationToken)).ConfigureAwait(false); } return(result == null ? null : persistenceContext.ProxyFor(result)); } catch (OperationCanceledException) { throw; } catch (HibernateException) { // Do not call Convert on HibernateExceptions throw; } catch (Exception sqle) { throw ADOExceptionHelper.Convert(factory.SQLExceptionConverter, sqle, "Error performing LoadByUniqueKey"); } }
/// <summary> /// Load an instance by a unique key that is not the primary key. /// </summary> /// <param name="entityName">The name of the entity to load </param> /// <param name="uniqueKeyPropertyName">The name of the property defining the unique key. </param> /// <param name="key">The unique key property value. </param> /// <param name="session">The originating session. </param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> /// <returns> The loaded entity </returns> public async Task <object> LoadByUniqueKeyAsync(string entityName, string uniqueKeyPropertyName, object key, ISessionImplementor session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ISessionFactoryImplementor factory = session.Factory; IUniqueKeyLoadable persister = (IUniqueKeyLoadable)factory.GetEntityPersister(entityName); //TODO: implement caching?! proxies?! var keyType = GetIdentifierOrUniqueKeyType(factory) .GetSemiResolvedType(factory); EntityUniqueKey euk = new EntityUniqueKey( entityName, uniqueKeyPropertyName, key, keyType, session.Factory); IPersistenceContext persistenceContext = session.PersistenceContext; try { object result = persistenceContext.GetEntity(euk); if (result == null) { result = await(persister.LoadByUniqueKeyAsync(uniqueKeyPropertyName, key, session, cancellationToken)).ConfigureAwait(false); if (result == null && !IsNullable) { factory.EntityNotFoundDelegate.HandleEntityNotFound(entityName, uniqueKeyPropertyName, key); } } return(result == null ? null : persistenceContext.ProxyFor(result)); } catch (OperationCanceledException) { throw; } catch (HibernateException) { // Do not call Convert on HibernateExceptions throw; } catch (Exception sqle) { throw ADOExceptionHelper.Convert(factory.SQLExceptionConverter, sqle, "Error performing LoadByUniqueKey"); } }