001: //$Id: ManyToOneType.java 10020 2006-06-15 16:38:03Z steve.ebersole@jboss.com $
002: package org.hibernate.type;
003:
004: import java.io.Serializable;
005: import java.sql.PreparedStatement;
006: import java.sql.ResultSet;
007: import java.sql.SQLException;
008: import java.util.Arrays;
009:
010: import org.hibernate.AssertionFailure;
011: import org.hibernate.HibernateException;
012: import org.hibernate.MappingException;
013: import org.hibernate.engine.EntityKey;
014: import org.hibernate.engine.ForeignKeys;
015: import org.hibernate.engine.Mapping;
016: import org.hibernate.engine.SessionImplementor;
017: import org.hibernate.persister.entity.EntityPersister;
018:
019: /**
020: * A many-to-one association to an entity.
021: *
022: * @author Gavin King
023: */
024: public class ManyToOneType extends EntityType {
025:
026: private final boolean ignoreNotFound;
027:
028: public ManyToOneType(String className) {
029: this (className, false);
030: }
031:
032: public ManyToOneType(String className, boolean lazy) {
033: super (className, null, !lazy, true, false);
034: this .ignoreNotFound = false;
035: }
036:
037: public ManyToOneType(String entityName,
038: String uniqueKeyPropertyName, boolean lazy,
039: boolean unwrapProxy, boolean isEmbeddedInXML,
040: boolean ignoreNotFound) {
041: super (entityName, uniqueKeyPropertyName, !lazy,
042: isEmbeddedInXML, unwrapProxy);
043: this .ignoreNotFound = ignoreNotFound;
044: }
045:
046: protected boolean isNullable() {
047: return ignoreNotFound;
048: }
049:
050: public boolean isAlwaysDirtyChecked() {
051: // If we have <tt>not-found="ignore"</tt> association mapped to a
052: // formula, we always need to dirty check it, so we can update the
053: // second-level cache
054: return ignoreNotFound;
055: }
056:
057: public boolean isOneToOne() {
058: return false;
059: }
060:
061: public int getColumnSpan(Mapping mapping) throws MappingException {
062: // our column span is the number of columns in the PK
063: return getIdentifierOrUniqueKeyType(mapping).getColumnSpan(
064: mapping);
065: }
066:
067: public int[] sqlTypes(Mapping mapping) throws MappingException {
068: return getIdentifierOrUniqueKeyType(mapping).sqlTypes(mapping);
069: }
070:
071: public void nullSafeSet(PreparedStatement st, Object value,
072: int index, boolean[] settable, SessionImplementor session)
073: throws HibernateException, SQLException {
074: getIdentifierOrUniqueKeyType(session.getFactory()).nullSafeSet(
075: st, getIdentifier(value, session), index, settable,
076: session);
077: }
078:
079: public void nullSafeSet(PreparedStatement st, Object value,
080: int index, SessionImplementor session)
081: throws HibernateException, SQLException {
082: getIdentifierOrUniqueKeyType(session.getFactory()).nullSafeSet(
083: st, getIdentifier(value, session), index, session);
084: }
085:
086: public ForeignKeyDirection getForeignKeyDirection() {
087: return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT;
088: }
089:
090: public Object hydrate(ResultSet rs, String[] names,
091: SessionImplementor session, Object owner)
092: throws HibernateException, SQLException {
093: // return the (fully resolved) identifier value, but do not resolve
094: // to the actual referenced entity instance
095: // NOTE: the owner of the association is not really the owner of the id!
096: Serializable id = (Serializable) getIdentifierOrUniqueKeyType(
097: session.getFactory()).nullSafeGet(rs, names, session,
098: null);
099: scheduleBatchLoadIfNeeded(id, session);
100: return id;
101: }
102:
103: /**
104: * Register the entity as batch loadable, if enabled
105: */
106: private void scheduleBatchLoadIfNeeded(Serializable id,
107: SessionImplementor session) throws MappingException {
108: //cannot batch fetch by unique key (property-ref associations)
109: if (uniqueKeyPropertyName == null && id != null) {
110: EntityPersister persister = session.getFactory()
111: .getEntityPersister(getAssociatedEntityName());
112: EntityKey entityKey = new EntityKey(id, persister, session
113: .getEntityMode());
114: if (!session.getPersistenceContext().containsEntity(
115: entityKey)) {
116: session.getPersistenceContext().getBatchFetchQueue()
117: .addBatchLoadableEntityKey(entityKey);
118: }
119: }
120: }
121:
122: public boolean useLHSPrimaryKey() {
123: return false;
124: }
125:
126: public boolean isModified(Object old, Object current,
127: boolean[] checkable, SessionImplementor session)
128: throws HibernateException {
129: if (current == null) {
130: return old != null;
131: }
132: if (old == null) {
133: // we already know current is not null...
134: return true;
135: }
136: // the ids are fully resolved, so compare them with isDirty(), not isModified()
137: return getIdentifierOrUniqueKeyType(session.getFactory())
138: .isDirty(old, getIdentifier(current, session), session);
139: }
140:
141: public Serializable disassemble(Object value,
142: SessionImplementor session, Object owner)
143: throws HibernateException {
144:
145: if (isNotEmbedded(session)) {
146: return getIdentifierType(session).disassemble(value,
147: session, owner);
148: }
149:
150: if (value == null) {
151: return null;
152: } else {
153: // cache the actual id of the object, not the value of the
154: // property-ref, which might not be initialized
155: Object id = ForeignKeys.getEntityIdentifierIfNotUnsaved(
156: getAssociatedEntityName(), value, session);
157: if (id == null) {
158: throw new AssertionFailure(
159: "cannot cache a reference to an object with a null id: "
160: + getAssociatedEntityName());
161: }
162: return getIdentifierType(session).disassemble(id, session,
163: owner);
164: }
165: }
166:
167: public Object assemble(Serializable oid,
168: SessionImplementor session, Object owner)
169: throws HibernateException {
170:
171: //TODO: currently broken for unique-key references (does not detect
172: // change to unique key property of the associated object)
173:
174: Serializable id = assembleId(oid, session);
175:
176: if (isNotEmbedded(session)) {
177: return id;
178: }
179:
180: if (id == null) {
181: return null;
182: } else {
183: return resolveIdentifier(id, session);
184: }
185: }
186:
187: private Serializable assembleId(Serializable oid,
188: SessionImplementor session) {
189: //the owner of the association is not the owner of the id
190: return (Serializable) getIdentifierType(session).assemble(oid,
191: session, null);
192: }
193:
194: public void beforeAssemble(Serializable oid,
195: SessionImplementor session) {
196: scheduleBatchLoadIfNeeded(assembleId(oid, session), session);
197: }
198:
199: public boolean[] toColumnNullness(Object value, Mapping mapping) {
200: boolean[] result = new boolean[getColumnSpan(mapping)];
201: if (value != null) {
202: Arrays.fill(result, true);
203: }
204: return result;
205: }
206:
207: public boolean isDirty(Object old, Object current,
208: SessionImplementor session) throws HibernateException {
209: if (isSame(old, current, session.getEntityMode())) {
210: return false;
211: }
212: Object oldid = getIdentifier(old, session);
213: Object newid = getIdentifier(current, session);
214: return getIdentifierType(session)
215: .isDirty(oldid, newid, session);
216: }
217:
218: public boolean isDirty(Object old, Object current,
219: boolean[] checkable, SessionImplementor session)
220: throws HibernateException {
221: if (isAlwaysDirtyChecked()) {
222: return isDirty(old, current, session);
223: } else {
224: if (isSame(old, current, session.getEntityMode())) {
225: return false;
226: }
227: Object oldid = getIdentifier(old, session);
228: Object newid = getIdentifier(current, session);
229: return getIdentifierType(session).isDirty(oldid, newid,
230: checkable, session);
231: }
232:
233: }
234:
235: }
|