Asp.net Multi Tenancy implementation on existing solution - asp.net

I have an asp.net MVC solution, Entity Framework code first, which has dozens of database tables all designed around a single company using the solution.
The requirement has come up to allow multiple companies to use the solution, so what we have done is add "CompanyID" as a column to all database tables and set a default value. There is a company table with the various company names and CompanyID's. On login the user selects the company they are logging in as which stores the CompanyID in the session.
At the moment every Entity Framework call now has to be updated to include the CompanyID, for example when selecting Employees I am doing:
List<Employee> employees = db.Employees.Where(x => x.CompanyID = Session.CompanyID).ToList();
As you can see it will be tedious to do this on thousands of calls to the db. Any update, save, and fetch has to change.
Surely I am doing it the long way and there is a way at runtime, globally to append all DB calls to include the CompanyID stored in the logged in users Session? Something that dynamically appends the CompanyID when fetching values or storing etc? Perhaps a package I can use to do this task at runtime?

In my opinion, there is no need to add CompanyID to EVERY table in the database. I would select just "root" tables/entities for that. For example, Employee or Department clearly sounds like a many-to-one relationship with a company - so adding CompanyID there sounds right. But, for example, EmployeeEquipment which is a many-to-one relationship with Employee does not have to have CompanyID column since it can be filtered by the joined Employee table.
Regarding your request to filter by CompanyID globally, I'm not aware of anything that can do that per request. There are global filters for Entity Framework, but I'm not sure how you can apply them per-request. Take a look on .HasQueryFilter() during model creation if you are using Entity Framework Core.

Related

Best method to retrieve Active Directory list using ASP.NET

I am fairly new to ASP.NET programming. I am designing a web project which will maintain employees information, such as the approval schema, staff inventories, claims, etc. The database will record the employee ID as the key. Currently there is no local table storing the mapping of the employee ID and employee name. These information will be retrieved from the Active Directory.
The new system will allow user to do employee lookup e.g. based on name or ID and generate report e.g. list of employee claims of the month. The lookup can be achieved by directly accessing the AD but I don't think it's a good method for generating list of employees/reports. Hence, I'm planning to download the AD list to local database.
My questions are:
1. Is downloading AD list to local database the right method for this situation? Is there any other alternatives to achieve this?
2. Shall I go with downloading the AD list, how to update it on regular basis? I can only think of clearing the table and reimport the whole list again.
Any advises will be much welcomed.
take a look at http://linqtoad.codeplex.com/ I've used it before with great success
"The new system will allow user to do employee lookup e.g. based on name or ID and generate report e.g. list of employee claims of the month."
Sounds like you do not need all employees from AD at once. In that case I would not download the AD list at all, as that would put you in a situation where you have to deal with your database being out of date.
Just start with retrieving the data from AD on request and only think about optimizations if you encounter performance problems.

Single website multiple databases, database switching

I have created a content management system (CMS) for my company’s product databases. The CMS is based on asp.net scaffolding with many custom pages and actions mixed in. We have 7 products currently, all of which share the same database schema (Entity Framework model-first) and all run perfectly in the CMS. The issue is that every time we get a new product we must clone the CMS and change the connection string in the app.config to point to the correct database in order to work with the new database. While this works, it’s becoming bothersome to maintain and will fail us completely as we acquire more products.
What I would like to do is have a centralized landing page where a user is directed to log in, then given the option to connect to and edit a specific product based on their selection. The idea is that we would have one CMS site which would be able to switch between the databases depending on the user. It is not an option to combine all of the product database in to a single master product database.
I am not sure where to start to achieve this goal, or if this is even the correct plan to achieve my goal of having a single CMS to maintain, and am looking for some guidance in this.
Assuming that your database structures are identical, you could use a factory method anywhere you get an instance of your entity context and put logic in there to grab the correct connection string (or calculate it if there's a naming convention that you could use). Something like this might work for example:
public static MyDatabaseEntities CreateEntityContext(string productName)
{
string connectionString = null;
switch (productName.Trim().ToLower())
{
case "apples":
connectionString = ConfigurationManager.ConnectionStrings["MyDatabase_Apples"].ConnectionString;
break;
case "pears":
connectionString = ConfigurationManager.ConnectionStrings["MyDatabase_Pears"].ConnectionString;
break;
default:
connectionString = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
break;
}
return new MyDatabaseEntities(connectionString);
}
Then use this method anywhere you need an instance of your CRM data context passing in the product name that you've calculated on your landing page.
Create another database for user to database mapping. The structure would be like so:
database UserMap
table Users
username (composite primary key)
dbID (composite primary key, foreign key to "Databases" table)
table Databases
dbID (primary key)
connectionString
Then,
populate the list of database in table "Databases"
Do your SQL work to copy the users from the other websites into this "UserMap" database
Write a trigger in each CMS database to add or remove a user as they are created or removed in their respective CMS so it updates the "UserMap" database
Modify your code on the CMS(s) to use this single database for lookup to what connection string should be used.
This would allow you to rely on the single database for the lookup and switch between them in a managed fashion going forward. It requires some up front work but after the triggers are there, you don't have to do anything more.

NHibernate - Exclude subclass using Criteria with Joined Subclass

I have a fluent nhibernate configuration in my app. Running latest of both. I am trying to create a criteria statement to pull back a specific class in a joined subclass hierarchy. This is an example of my inheritance structure:
Admin is an Employee is a Person (Admin : Employee, Employee : Person)
What I am trying to get is the Employees but not the Admins, but since admins are employees, they are coming back in the query. I do not have a discriminator column to use. Is there any way to accomplish this using the Criteria API?
Thanks in advance.
Schema as requested (just an example):
Person table: Id, Name
Employee table: PersonId, EmployeeNumber
Admin: PersonId, AdminNumber
NHibernate relates those properly. Everything else works except this specific type of query.
It appears that Criteria does not support that functionality. I was able to solve the issue by adding a SQL Restriction to the query to filter out the subclass results.
criteria.Add(
Expression.SQL("{alias}.MyPrimaryKey NOT IN (SELECT MyPrimaryKey FROM Admin)"));
This essentially excludes and results from the Employee SQL query where that Employee exists in the Admin table, thus returning only Employees that are not Admins.
I originally tried separately querying the Admin table via Criteria to get a list of Ids which I then fed into the Employee query using a NOT IN Criteria statement Restrictions.Not(Restrictions.In()) but SQL Server restricts the number of parameters to 2100 and blows up if that collection of Ids that you are trying to exclude has more than 2100 items.

Using ExecuteQuery() with entity framework, entity class

I am trying to jump from ASP Classic to asp.net. I have followed tutorials to get Entity Framework and LINQ to connect to my test database, but I am having difficulties figuring out ExecuteQuery(). I believe the problem is that I need an "entity class" for my database, but I can't figure out how to do it. Here is my simple code:
Dim db as New TestModel.TestEntity
Dim results AS IEnumerable(OF ???) = db.ExecuteQuery(Of ???)("Select * from Table1")
From the microsoft example site, they use an entity class called Customers, but I don't understand what that means.
Entity Framework comes with a visual designer. In that designer, you connect to your existing database, and you select all the tables (and possibly views) from your database that you want to work with.
From that selection, EF will generate entity classes one for each of your tables, e.g. if you have a Customers table, you'll get a Customer class, if you have a Products table, you get a Product class.
Those classes represent (by default) your table structure 1:1 - e.g. each column in your table gets translated into a property on the class.
Once you have that, you're no longer dealing with SQL statements and stuff like ExecuteQuery() - you leave that to EF to handle for you.
You just ask for what you need, e.g. all your customers from a given state:
var ohioCustomers = from c in dbContext.Customers
where c.State = "OH"
select c;
This statement will return an IEnumerable<Customer> - a list of customers that matches your search criteria.

LINQ to Entities, several one-to-one references to the same tables and naming

I've started porting a .NET SQL Server application to LINQ to Entities. I have (among others...) one table called Users, and one called Time. Time is reported on a specific user (UserId), but it is also recorded which user made the report (InsertedByUserId) and possibly who has updated the Time since insert (UpdatedByUserId). This gives me three references to the table Users.
When I generate a .EDMX from this I get three references to the table Users: User, User1 and User2. Without manual edit I have no way of knowing which one refers to the UserId, InsertedByUserId or UpdatedByUserId field.
How do others solve this? Maybe it's not necessary to register ALL references, and stick with InsertedByUserId and UpdatedByUserId as ints?
(The manual edit wouldn't be a problem if the database were never updated, but as we make changes to the database every now and then we occasionally have to regenerate the .EMDX, thus removing all manual changes.)
Thanks in advance!
Jos,
Generally when I make my foreign keys, I name them accordingly. From the Entity designer you can differentiate between the different Navigation Properties (ie User, User1, User2) by looking at the FK association (as long as you named your foreign keys distinctly). For Instance I have a ModifiedById and CreatedById field in each table. Both fields reference my SystemUser table, My foreign keys are named like this: FK_[TableName]_SystemUser_CreatedBy and FK_[TableName]_SystemUser_ModifiedBy.
You should notice that in the Navigation properties you can see the Foreign key. You can also modify the name of the Navigation Property (which is in the Conceptual Side "CSDL portion" of the EDMX), and this change will stay when you update your EDMX from the database.

Resources