/// <summary> /// Register multiple types. Calling this method makes Gentle create an ObjectMap /// for all supported types in the assembly. /// If schema data is needed the supplied <see cref="PersistenceBroker"/> /// instance will be used. /// </summary> /// <param name="broker">The <see cref="PersistenceBroker"/> instance used to obtain /// metadata from the database schema.</param> /// <param name="assembly">The assembly whose types should be registered.</param> public static void RegisterAssembly(PersistenceBroker broker, Assembly assembly) { foreach (Type type in assembly.GetTypes()) { RegisterType(broker, type); } }
public IEntity Construct(int columnComboHashCode, object[] row, PersistenceBroker broker) { // TODO improve error msg Check.Verify(constructorMaps.ContainsKey(columnComboHashCode), Error.Unspecified, "Invalid columnComboHashCode parameter (no associated ConstructorMap instance)."); ConstructorMap cm = constructorMaps[columnComboHashCode] as ConstructorMap; IEntity result = null; // perform object uniqing and caching if (GentleSettings.CacheObjects && objectMap.CacheStrategy != CacheStrategy.Never) { string key = cm.GetRowHashKey(row); result = CacheManager.Get(key) as IEntity; if (result == null) { result = cm.Construct(row, broker); CacheManager.Insert(key, result, objectMap.CacheStrategy); } else { GentleStatistics.UniqingCount += 1; } } else { result = cm.Construct(row, broker); } return(result); }
/// <summary> /// Register a single type. Calling this method makes Gentle create an ObjectMap /// for the given type. /// If schema data is needed the supplied <see cref="PersistenceBroker"/> /// instance will be used. This method will silently ignore unsupported types and is /// therefore safe to call with any type. /// </summary> /// <param name="broker">The <see cref="PersistenceBroker"/> instance used to obtain /// metadata from the database schema.</param> /// <param name="type">The type for which to create an ObjectMap.</param> public static void RegisterType(PersistenceBroker broker, Type type) { if (IsTypeSupported(type)) { GetMap(broker, type); } }
/// <summary> /// Process the given type and construct the corresponding ObjectMap instance. If the /// map has been created previously a cached instance is returned. /// </summary> /// <param name="broker">The PersistenceBroker to use for obtaining metadata on the type. If /// null is passed the DefaultProvider will be used.</param> /// <param name="type">The type to process</param> /// <returns>An ObjectMap instance describing the type</returns> public static ObjectMap GetMap(PersistenceBroker broker, Type type) { ObjectMap om = null; lock (maps.SyncRoot) { if (!maps.ContainsKey(type)) { if (broker == null) { IGentleProvider provider = ProviderFactory.GetProvider(type); broker = provider.Broker; } om = ConstructMap(broker, type); maps[type] = om; } else { om = (ObjectMap)maps[type]; } } // throw an exception for unsupported types Check.VerifyNotNull(om, Error.UnsupportedType, type); return(om); }
private static ObjectView GetObjectView(PersistenceBroker broker, Type type, string viewName) { ObjectMap map = ObjectFactory.GetMap(broker, type); Check.VerifyNotNull(viewName, Error.NullParameter, "viewName"); ObjectView view = map.Views[viewName] as ObjectView; Check.VerifyNotNull(view, Error.NoSuchView, viewName, type); return(view); }
/// <summary> /// Construct a TableMap instance to hold information on the given table. /// </summary> /// <param name="broker">The PersistenceBroker instance used to obtain metadata on the table. /// If null is passed the DefaultProvider settings will be used.</param> /// <param name="tableName">The name of the table for which to hold information.</param> public TableMap(PersistenceBroker broker, string tableName) : base(broker) { provider = SessionBroker.Provider; // use property accessor to also set quoted name if (tableName != null) { TableName = tableName; } fields = new FieldList(); }
/// <summary> /// Construct a new SqlStatement instance of the specified type. The command object to be used /// for executing the query and the fully specified sql query string must be specified. /// </summary> /// <param name="broker">The PersistenceBroker instance to use for database access.</param> /// <param name="stmtType">The type of this statement.</param> /// <param name="cmd">The command object to use when executing the query.</param> /// <param name="sql">The fully specified sql query string.</param> /// <param name="type">The type of object being selected by this query or null if /// not applicable.</param> /// <param name="rowLimit">The maximum number of rows to be returned by this query /// or 0 for no limit.</param> /// <param name="rowOffset">The number of rows to be skipped by this statement. Note that /// for SQL Server this is applied after execution, whereas for other databases it is /// embedded in the SQL string.</param> public SqlStatement(PersistenceBroker broker, StatementType stmtType, IDbCommand cmd, string sql, Type type, int rowLimit, int rowOffset) : base(broker, type) { this.cmd = cmd; cmd.CommandText = sql; statementType = stmtType == StatementType.Unknown ? GetStatementType(sql) : stmtType; map = type != null?ObjectFactory.GetMap(broker, type) : null; this.rowLimit = rowLimit; this.rowOffset = rowOffset; }
/// <summary> /// Process the given object's type and construct the corresponding ObjectMap instance. If the /// map has been created previously a cached instance is returned. /// </summary> /// <param name="broker">The PersistenceBroker to use for obtaining metadata on the type. If /// null is passed the DefaultProvider will be used.</param> /// <param name="obj">The instance to process</param> /// <returns>An ObjectMap instance describing the type</returns> public static ObjectMap GetMap(PersistenceBroker broker, object obj) { Check.VerifyNotNull(obj, Error.NullParameter, "obj"); Type type = obj.GetType(); if (type == typeof(string)) { return(GetMap(obj as string)); } return(GetMap(broker, obj.GetType())); }
/// <summary> /// Retrieve the object of the specified type and identified by the given key. This method will /// throw an exception if not exactly one row in the database matches. /// </summary> /// <param name="broker">The PersistenceBroker and associated provider used fetch the data</param> /// <param name="type">The type of the Persistent descendant</param> /// <param name="key">The key identifying the object</param> /// <returns>An object instance of the specified type</returns> public static object Retrieve(PersistenceBroker broker, Type type, Key key) { if (broker == null) { // use default broker instance by use of the Broker class return(Broker.RetrieveInstance(type, key)); } else // use supplied broker instance { return(broker.RetrieveInstance(type, key)); } }
/// <summary> /// Construct an object instance using the data supplied in the key. The type for which this /// is a map is scanned for constructors that can be used with the available keys from the /// given Key instance. /// </summary> /// <param name="key">A full set of key/value pairs to use for constructing the object. The /// type being constructed must have a constructor with exactly the number of arguments /// contained in the given Key instance.</param> /// <param name="broker">The PersistenceBroker instance used to fetch the current row</param> /// <returns>An instance of the given type</returns> /// <exception cref="GentleException"> will be raised if no object could be created</exception> internal object Construct(Key key, PersistenceBroker broker) { // split key into seperate arrays of property names and their values string[] names = new string[key.Count]; key.Keys.CopyTo(names, 0); object[] values = new object[key.Count]; key.Values.CopyTo(values, 0); // find constructor to use int hash = objectConstructor.DetermineConstructor(names, values); return(Construct(hash, values, broker)); }
/// <summary> /// Retrieve all objects of a certain type (plain select of all rows in a the /// table, i.e. a statement without any where-clause). /// </summary> /// <param name="broker">The PersistenceBroker and associated provider used fetch the data</param> /// <param name="type">The type of the Persistent descendant to retrieve</param> /// <returns>A collection of objects of the given type</returns> public static IList RetrieveList(PersistenceBroker broker, Type type) { if (broker == null) { // use default broker instance by use of the Broker class return(Broker.RetrieveList(type)); } else // use supplied broker instance { return(broker.RetrieveList(type)); } }
/// <summary> /// Construct an ObjectMap instance for the given type. /// </summary> /// <param name="broker">The PersistenceBroker instance to which this map is related.</param> /// <param name="type">The type for which this instance is a map</param> public ObjectMap(PersistenceBroker broker, Type type) : base(broker) { this.type = type; if (type != null) { SetTableName(type); } //this.dbMaps = new Hashtable(); views = new Hashtable(); validations = new ArrayList(); objectConstructor = new ObjectConstructor(this); }
/// <summary> /// This is the generic base constructor will a full argument set. /// </summary> /// <param name="version">The version of this record in the database or 0 for new instances.</param> /// <param name="isPersisted">A boolean to indicate whether this object has been persisted.</param> /// <param name="broker">The PersistenceBroker to use for connecting to the database.</param> public ContextPersistent(int version, bool isPersisted, PersistenceBroker broker) { databaseVersion = version; this.isPersisted = isPersisted; if (broker == null) { this.broker = new PersistenceBroker(GetType()); } else // use supplied broker and associated provider { this.broker = broker; } }
/// <summary> /// Use this constructor to create lists that represent n:m relations. This class /// automatically calls Persist() and Remove() on objects when they are added or removed /// from the list. Additionally, the relation objects linking the parent and the contained /// objects are automatically created and destroyed as objects are added or removed from /// the list, thus making the n:m relationship transparent to clients. /// </summary> /// <param name="broker">The PersistenceBroker to use for connecting to the database.</param> /// <param name="containedType">The type of objects stored in this list instance. The contained /// type must be supported by Gentle and implement the IPersistent interface.</param> /// <param name="parent">The parent of the contained objects. A parent is required for /// managing 1:n and n:m relations.</param> /// <param name="viaType">The type of objects used to represent the n:m relationship.</param> /// <param name="relationTypes">Additional types from which to extract information when /// creating relations. This is only used in n:m scenarios and permits you to have /// relation tables with more than just two columns. The PK is extracted from the /// specified types (so you cannot use any member; only PKs can be stored).</param> public GentleList(PersistenceBroker broker, Type containedType, IPersistent parent, Type viaType, params Type[] relationTypes) { this.broker = broker != null ? broker : new PersistenceBroker(containedType); InitType(containedType, parent, viaType); // trigger additional initialization only for managed relationships if (listType == GentleListType.OneToMany || listType == GentleListType.ManyToMany) { InitParent(parent); } // populate list with existing data InitList(viaType, relationTypes); }
/// <summary> /// Obtain a new key for the specified object instance. The returned key will contain the /// primary keys of the given instance. /// </summary> /// <param name="broker">The optional PersistenceBroker instance to use for obtaining the /// ObjectMap for the supplied object instance. If this parameter is null, Gentle will try /// to infer the broker from the object instance. If that fails, it will use the default /// provider.</param> /// <param name="key">An optional existing key to add the values to</param> /// <param name="isPropertyKeys">False is key indexers are column names, true for property names</param> /// <param name="instance">The object instance whose property values will be used</param> /// <returns>A key instance containing the primary key values of the given object instance</returns> public static Key GetKey(PersistenceBroker broker, Key key, bool isPropertyKeys, object instance) { // try to infer broker from instance if (broker == null && instance is IBrokerLock) { broker = (instance as IBrokerLock).SessionBroker; } // WARNING/TODO if broker is null here and no ObjectMap yet exists for the type, // the DefaultProvider will be used to create the ObjectMap ObjectMap map = ObjectFactory.GetMap(broker, instance); return(GetKey(broker, key, isPropertyKeys, instance, map.GetPrimaryKeyNames(isPropertyKeys))); }
/// <summary> /// Constructor for error conditions. /// </summary> /// <param name="broker">The PersistenceBroker instance to use for database access.</param> /// <param name="error">The exception raised by the .NET framework</param> public SqlResult(PersistenceBroker broker, Exception error) : base(broker) { this.error = error; // SQL Server specific: if (error.GetType().Equals(typeof(SqlException))) { errorCode = ((SqlException)error).Number; } else { errorCode = 42; // it's magic } }
/// <summary> /// Constructor for the GentleAnalyzer base class. /// </summary> /// <param name="provider"></param> protected GentleAnalyzer(IGentleProvider provider) { this.provider = provider; if (maps == null) { maps = new Hashtable(); done = false; } // make sure we use our own PB to avoid using the DefaultProvider when analyzing the database broker = new PersistenceBroker(provider); // this.broker = new PersistenceBroker( provider.Name, provider.ConnectionString ); // set the default analyzer level level = GentleSettings.AnalyzerLevel; }
protected BrokerLock(PersistenceBroker broker, Type type) { if (broker == null) { if (type == null) { type = GetType(); } this.broker = new PersistenceBroker(type); } else // use supplied broker and associated provider { this.broker = broker; } }
/// <summary> /// Obtain a key for the specified object instance and property names. The returned /// key will contain the corresponding column names for the type, and thus foreign /// key columns must use identical naming for this to work. /// </summary> /// <param name="broker">The optional PersistenceBroker instance to use for obtaining the /// ObjectMap for the supplied object instance. If this parameter is null, Gentle will try /// to infer the broker from the object instance. If that fails, it will use the default /// provider.</param> /// <param name="key">An optional existing key to add the values to</param> /// <param name="isPropertyKeys">False is key indexers are column names, true for property names</param> /// <param name="instance">The object instance whose property values will be used</param> /// <param name="members">The names of the properties to include in the key</param> /// <returns>The key</returns> public static Key GetKey(PersistenceBroker broker, Key key, bool isPropertyKeys, object instance, params string[] members) { Check.VerifyNotNull(instance, Error.NullParameter, "instance"); // try to infer broker from instance if (broker == null && instance is IBrokerLock) { broker = (instance as IBrokerLock).SessionBroker; } // WARNING/TODO if broker is null here and no ObjectMap yet exists for the type, // the DefaultProvider will be used to create the ObjectMap ObjectMap map = ObjectFactory.GetMap(broker, instance); // only set source type reference if this is a new key if (key == null) { key = new Key(map.GetTableName(instance), instance.GetType(), isPropertyKeys); } //else // Check.Verify( ! key.isPropertyKeys, Error.DeveloperError, // "Unable to combine keys containing property names due to possible name clashes." ); Check.VerifyEquals(key.isPropertyKeys, isPropertyKeys, "Cannot combine property and " + "column names in a single key - use one or the other."); Check.VerifyNotNull(members, Error.NullParameter, "members"); // process the list of specified properties foreach (string memberName in members) { FieldMap fm = isPropertyKeys ? map.GetFieldMap(memberName) : map.GetFieldMapFromColumn(memberName); Check.VerifyNotNull(fm, Error.NoProperty, map.Type, memberName); // FIXME outdated error message object memberValue = fm.GetValue(instance); // translate foreign references to local names if (key.SourceType != map.Type) { // WARNING/TODO if broker is null here and no ObjectMap yet exists for the type, // the DefaultProvider will be used to create the ObjectMap ObjectMap keyMap = ObjectFactory.GetMap(broker, key.SourceType); fm = keyMap.GetForeignKeyFieldMap(map.TableName, fm.ColumnName); } key[isPropertyKeys ? fm.MemberName : fm.ColumnName] = memberValue; } // add concurrency value if enabled and instance has revision column if (GentleSettings.ConcurrencyControl && map.ConcurrencyMap != null) { long version = Convert.ToInt64(map.ConcurrencyMap.GetValue(instance)); key[isPropertyKeys ? map.ConcurrencyMap.MemberName : map.ConcurrencyMap.ColumnName] = version; } return(key); }
/// <summary> /// Create a new list for storing the specified type of objects. /// </summary> public GentleRelation(PersistenceBroker broker, Type containedType, IPersistent parent, params Type[] relatedTypes) : base(broker) { Check.VerifyNotNull(relatedTypes, Error.NullParameter, "relatedTypes"); /*Check.Verify( parent == null && relatedTypes.Length == 2 || * parent != null && relatedTypes.Length == 1, Error.NotImplemented, * "The GentleRelation class is currently only able to manage two-way relations." ); */ this.relatedTypes = relatedTypes; this.parent = parent; containedMap = ObjectFactory.GetMap(broker, containedType); // note: "this." required on broker param or original null param might get passed relations = new GentleList(this.broker, containedType, parent); // verify that the linked types are supported by Gentle foreach (Type relatedType in relatedTypes) { Check.Verify(relatedType.IsSubclassOf(typeof(Persistent)) || relatedType.GetInterface("IPersistent") != null, Error.UnsupportedType, relatedType); } }
/// <summary> /// Retrieve a statement from the cache. If the statement is not present it will be generated /// and added to the cache. /// </summary> /// <param name="type">The business object with which the statement is associated</param> /// <param name="tableName">The table used in the statement</param> /// <param name="stmtType">The type of the SQL statement</param> /// <returns>An SqlStatement instance</returns> public SqlStatement GetStatement(Type type, string tableName, StatementType stmtType) { Initialize(); // ensure thread local variables have been initialized SqlStatement stmt; Hashtable stmts = (Hashtable)stmtByType[type]; // check if an SqlStatement has been cached for the given type and StatementType bool isCached = stmts != null && stmts.ContainsKey(stmtType); if (isCached) { stmt = (SqlStatement)stmts[stmtType]; // the npgsql library for postgres does not allow us to update the connection // property when a transaction is active if (stmt.Command.Connection == null || providerName != "PostgreSQL") { // make sure statement broker reference is updated before returning it stmt.SessionBroker = Broker; return(stmt); } } // otherwise create and return fresh object PersistenceBroker broker = new PersistenceBroker(this); SqlBuilder sb = new SqlBuilder(broker, stmtType, type); // set the table name specified in the key (if null the default will be used instead) sb.SetTable(tableName); // get the statement using primary key fields as constraints stmt = sb.GetStatement(false); // dont cache statements for objects that map to multiple tables ObjectMap map = ObjectFactory.GetMap(broker, type); if (!(map.IsDynamicTable || isCached)) { // TODO Prepare only works with a connection :-( // stmt.Prepare(); CacheStatement(type, stmtType, stmt); } return(stmt); }
/// <summary> /// Constructor for ExecuteScalar results. /// </summary> /// <param name="broker">The PersistenceBroker instance to use for database access.</param> /// <param name="retval">The object returned by the .NET database provider.</param> /// <param name="stmt">The SqlStatement leading to this SqlResult</param> public SqlResult(PersistenceBroker broker, object retval, SqlStatement stmt) : base(broker) { this.stmt = stmt; if (retval != null) { try { // some rdbms' return 64-bit row identities long lastId = Convert.ToInt64(retval); returnValue = Convert.ToInt32(lastId); if (stmt.StatementType != StatementType.Count) { rowsAffected = 1; } } catch (Exception e) { throw new GentleException(Common.Error.NoIdentityReturned, stmt.Sql, e); } } }
public IEntity Construct(object[] row, PersistenceBroker broker) { object result; // if row content and element order matches constructor exactly if (isPerfectMatch) { result = constructorInfo.Invoke(Reflector.InstanceCriteria, null, row, null); } else { object[] constructorParams = GetParams(row); result = constructorInfo.Invoke(Reflector.InstanceCriteria, null, constructorParams, null); if (AnySet(columnReflectionMask)) { UpdateMembers(result, row); } } if (broker != null && result is BrokerLock) { (result as BrokerLock).SessionBroker = broker; } return(result as IEntity); }
/// <summary> /// Use this constructor to create lists of persistent objects that are not related to /// a parent object. This class automatically calls Persist() and Remove() on objects /// when they are added or removed from the list. /// </summary> /// <param name="broker">The PersistenceBroker to use for connecting to the database.</param> /// <param name="containedType">The type of objects to store. The given type must be a /// descendant of the Persistent class or implement the IPersistent interface.</param> public GentleList(PersistenceBroker broker, Type containedType) : this(broker, containedType, null, null) { }
/// <summary> /// Obtain a new key for the specified object instance. The returned key will contain the /// primary keys of the given instance. /// </summary> /// <param name="broker">The optional PersistenceBroker instance to use for obtaining the /// ObjectMap for the supplied object instance. If this parameter is null, Gentle will try /// to infer the broker from the object instance. If that fails, it will use the default /// provider.</param> /// <param name="isPropertyKeys">False is key indexers are column names, true for property names</param> /// <param name="instance">The object instance whose property values will be used</param> /// <returns>A key instance containing the primary key values of the given object instance</returns> public static Key GetKey(PersistenceBroker broker, bool isPropertyKeys, object instance) { return(GetKey(broker, null, isPropertyKeys, instance)); }
/// <summary> /// Obtain a new key for the specified object instance and property names. The returned /// key will contain the corresponding column names for the type, and thus foreign /// key columns must use identical naming for this to work. /// </summary> /// <param name="broker">The optional PersistenceBroker instance to use for obtaining the /// ObjectMap for the supplied object instance. If this parameter is null, Gentle will try /// to infer the broker from the object instance. If that fails, it will use the default /// provider.</param> /// <param name="isPropertyKeys">False is key indexers are column names, true for property names</param> /// <param name="instance">The object instance whose property values will be used</param> /// <param name="properties">The names of the properties to include in the key</param> /// <returns>The requested key</returns> public static Key GetKey(PersistenceBroker broker, bool isPropertyKeys, object instance, params string[] properties) { return(GetKey(broker, null, isPropertyKeys, instance, properties)); }
/// <summary> /// Create a new list for storing the specified type of objects. /// </summary> public GentleRelation(PersistenceBroker broker, Type containedType, params Type[] relatedTypes) : this(broker, containedType, null, relatedTypes) { }
/// <summary> /// Use this This is the recommended constructor /// The supplied PersistenceBroker instance will be used to access the database. /// </summary> /// <param name="isPersisted">A boolean to indicate whether this object has been persisted.</param> /// <param name="broker">The PersistenceBroker to use for connecting to the database.</param> protected Persistent(bool isPersisted, PersistenceBroker broker) : base(broker) { this.isPersisted = isPersisted; }
/// <summary> /// Clear the current PersistenceBroker instance used by the Broker class. This is /// useful if you have changed the Config.DefaultProvider setting. /// </summary> public static void ClearPersistenceBroker() { _broker = null; }
/// <summary> /// Use this constructor to create lists that represent 1:n relations. The relations between /// the contained objects and the parent instance are automatically maintained. This class /// automatically calls Persist() and Remove() on objects when they are added or removed /// from the list. /// </summary> /// <param name="broker">The PersistenceBroker to use for connecting to the database.</param> /// <param name="parent">The parent of the contained objects. A parent is required for /// managing 1:n and n:m relations.</param> /// <param name="containedType">The type of objects stored in this list instance. The contained /// type must be supported by Gentle and implement the IPersistent interface.</param> public GentleList(PersistenceBroker broker, Type containedType, IPersistent parent) : this(broker, containedType, parent, null) { }