Mehrmietunterstützung für ein einzelnes Datenbank Shared SchemaC#

Ein Treffpunkt für C#-Programmierer
Anonymous
 Mehrmietunterstützung für ein einzelnes Datenbank Shared Schema

Post by Anonymous »

Wir verwenden eine einzelne Datenbank mit einem gemeinsam genutzten Schema-Multi-Messen-Modell, da es die praktischste Möglichkeit ist, eine große Anzahl von Mietern zu unterstützen. Ansatz in NPGSQL, um eine Mieterbedingung automatisch in der Where -Klausel aller Abfragen anzuhängen, sodass Entwickler sie nicht manuell in jede SQL -Anweisung einbeziehen müssen? < /p>
Zum Beispiel, wenn ein Entwickler schreibt: < /p>

Code: Select all

SELECT * FROM order;
< /code>
Das System sollte es automatisch in: < /p>
umwandelnSELECT * FROM order WHERE tenantid = ;
< /code>
Vor der Ausführung.CREATE TABLE order (
id INT NOT NULL,
tenantid INT NOT NULL,
name VARCHAR(255)
);
< /code>
Wir suchen nach einer Möglichkeit, dies konsistent innerhalb von NPGSQL durchzusetzen (ohne Entitäts -Framework verwenden wir Basis ngpsql). < /p>
Der Ansatz, den wir sind Der Versuch ist es, einen benutzerdefinierten Befehlshandler zu erstellen. Dies erfordert jedoch eine Menge Bedingung, wie im unteren Codeblock gezeigt.  Was ist der beste Ansatz, um dies zu erreichen? < /P>
using Npgsql;
using System;
using System.Text.RegularExpressions;

public class TenantAwareCommand : NpgsqlCommand
{
private readonly TenantContext _tenantContext;

public TenantAwareCommand(string commandText, NpgsqlConnection connection, TenantContext tenantContext)
: base(commandText, connection)
{
_tenantContext = tenantContext;
}

public override async Task ExecuteReaderAsync(CommandBehavior behavior, System.Threading.CancellationToken cancellationToken)
{
AppendTenantIdCondition();
return await base.ExecuteReaderAsync(behavior, cancellationToken);
}

public override async Task ExecuteNonQueryAsync(System.Threading.CancellationToken cancellationToken)
{
AppendTenantIdCondition();
return await base.ExecuteNonQueryAsync(cancellationToken);
}

public override async Task ExecuteScalarAsync(System.Threading.CancellationToken cancellationToken)
{
AppendTenantIdCondition();
return await base.ExecuteScalarAsync(cancellationToken);
}

private void AppendTenantIdCondition()
{
if (string.IsNullOrEmpty(_tenantContext.TenantId))
throw new InvalidOperationException("Tenant ID is not set.");

// Normalize SQL by removing extra whitespaces to avoid errors in parsing
string normalizedQuery = Regex.Replace(CommandText, @"\s+", " ").Trim();

// If the query has no WHERE clause, add the TenantId filter as the first condition
if (!normalizedQuery.Contains("WHERE", StringComparison.OrdinalIgnoreCase))
{
CommandText = $"{CommandText} WHERE TenantId = '{_tenantContext.TenantId}'";
}
else
{
// If there is a WHERE clause, append the TenantId condition using AND
if (!normalizedQuery.Contains("TenantId", StringComparison.OrdinalIgnoreCase))
{
// Ensure it's added as an AND condition if there are already other conditions
CommandText = AppendTenantConditionToExistingWhereClause(normalizedQuery);
}
}
}

private string AppendTenantConditionToExistingWhereClause(string query)
{
// Match the position of the WHERE clause or subqueries to correctly append the TenantId condition
var whereIndex = query.IndexOf("WHERE", StringComparison.OrdinalIgnoreCase);

// If there's an existing WHERE clause, we append with AND
if (whereIndex >= 0)
{
string beforeWhere = query.Substring(0, whereIndex + 5); // "WHERE" + space
string afterWhere = query.Substring(whereIndex + 5).Trim();

// Check if the afterWhere already starts with an AND or other conditions
if (string.IsNullOrEmpty(afterWhere) || afterWhere.StartsWith("AND", StringComparison.OrdinalIgnoreCase))
{
return $"{beforeWhere} TenantId = '{_tenantContext.TenantId}' AND {afterWhere}";
}
else
{
return $"{beforeWhere} TenantId = '{_tenantContext.TenantId}' AND {afterWhere}";
}
}
else
{
// Default case if WHERE is not present but should be handled with OR
return $"{query} WHERE TenantId = '{_tenantContext.TenantId}'";
}
}
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post