New Posts New Posts RSS Feed: Multi-Tenant Database
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Multi-Tenant Database

 Post Reply Post Reply
Author
gavin.dell View Drop Down
Newbie
Newbie
Avatar

Joined: 08-Jul-2008
Posts: 1
Post Options Post Options   Quote gavin.dell Quote  Post ReplyReply Direct Link To This Post Topic: Multi-Tenant Database
    Posted: 08-Jul-2008 at 10:51pm
Hi there,

I am in the process of evaluating DevForce as a potential fit for our Data Access and Business Object requirements. At this point, I have one question:

We have a multi-tenant data store (SQL Server 2005) which requires the execution of a block of SQL (or a stored procedure) before the any SQL statements are executed against the connection.  This stored procedure sets the "tenant" state for the duration of this connection.  In some other ORM's that I have come across, you can specify a SQL statement to execute before using the connection - usually touted as connection validation SQL - and this suits our purposes. Does DevForce have a similar mechanism or is there some functionality we can implement to provide this?

Many thanks.

Gavin
Back to Top
davidklitzke View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 14-Jun-2007
Posts: 715
Post Options Post Options   Quote davidklitzke Quote  Post ReplyReply Direct Link To This Post Posted: 09-Jul-2008 at 8:17am
We have recently had one customer develop an application with multi-tenant capabilities.  They did this using a capability that you describe in your post.  This capability allows you to modify every outgoing query to the database.  In the example below from the "Best Practices" section of the Developer's Guide, this capabability can be used to implement "Soft Deletes", bur as I said earlier, we successfully used this same capability to implement mult-tenant database queries:
 

     Implementing “Soft Deletes”

Question: “For some of our Entities, we want the corresponding database records not to be physically deleted when a User deletes the Entity and saves changes. Instead, the corresponding record should just be flagged as deleted in the database.

“To accomplish this, we have a Status column that contains an enum value stating whether the row is deleted or not. When querying tables that include such columns, the Status always needs to be specified as a parameter to filter out the deleted records.

“I did not find an obvious way to implement this delete behaviour in our Entity classes.  Do you have any samples?

“Also, how can we extend or override DevForce’s GetEntity() methods so they filter out the deleted entities by default, without any additional clause?”

Answer: This is a pattern we often see. There are a number of ways to go about this:

1.                    Add a "Fetching" handler to the PersistenceManager that examines the query and adds this clause if necessary. The Fetching event is raised just before the PersistenceManager sends a query to the server; the query is included in the event args for the Fetching handler, and you can modify it before DevForce applies it.

2.                    Add a "Fetched" handler to the PersistenceManager that removes "inactive" entities from the cache if they happen to be picked up (e.g., through a span).  This is essential if you add spans that could retrieve an "inactive/deleted" record. You will want to use the overload of PersistenceManager.RemoveEntities() method that does not disturb the query cache.

3.                    Create a custom subclass of RdbQuery that always adds this clause.  Then always use your class instead of the raw RdbQuery.

4.                    Write your own PersistenceManager adapter that covers GetEntities, etc.

The "Fetching" and "Fetched" event handlers are strong candidates because they work even within Relation Properties. Consider, for example, Order.OrderDetails. If the OrderDetail object has an " ActiveFlag  column, you have to intercept the hidden query either by the use of a "Fetching" handler, or by overriding the "OrderDetails" property itself.

Let's assume that all business objects that have an "ActiveFlag" property descended from an abstract entity class (e.g., "ActiveEntity").

You might initialize your PersistenceManager as follows:

private void InitializePm() {

  mManager = PersistenceManager.DefaultManager;

  // other stuff

  mManager.Fetching += new EventHandler<EntityFetchingEventArgs>(mManager_Fetching);

  mManager.Fetched += new EventHandler<EntityFetchedEventArgs>(mManager_Fetched);

}

 

 

static void mManager_Fetching(object sender, EntityFetchingEventArgs e) {

  IdeaBlade.Persistence.Rdb.RdbQuery q = e.Query;

  if ( q.EntityType is ActiveEntity ) {

    q.AddClause("ActiveFlag", EntityQueryOp.EQ, true); // '1' == true

  }

}

 

static void mManager_Fetched(object sender, EntityFetchedEventArgs e) {

  List<Entity> removeList = new List<Entity>();

  foreach ( Entity obj in e.Entities ) {

    ActiveEntity ae = obj as ActiveEntity;

    if (ae != null && !ae.IsActive) {

      removeList.Add(obj);

    }

  }

  mManager.RemoveEntities(removeList, false); // remove but don't clear query cache.

}

There is another approach that might tempt you, but which should be avoided. There is an "SQL Where Clause" mapping option which lets you put a filtering constraint in the object definition itself. This is great if the value of the filter column is invariant. It is not good if the value of the filter column can change -- as is the case with the "inactive" or "deleted" column.  Therefore, do not consider this option.



Edited by davidklitzke - 09-Jul-2008 at 8:20am
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down