Eu tenho uma Settings
mesa e uma Tenant
mesa. Existe uma hierarquia para que um Account
pode ter 1 ou muitos Companies
e um Company
pode ter 1 ou muitos 'Instalações'.
Account 1
---> Company 1
---> Facility 1
---> Facility 2
---> Company 2
---> Facility 3
---> Facility 4
Eles podem ter uma configuração padrão que se aplica a toda a conta....
| FacilityId | CompanyId | AccountId | SettingValue |
|------------|-----------|-----------|--------------|
| (null) | (null) | 1 | 5 |
...exceto que eles têm uma substituição para a Instalação 3 que se aplica apenas à Instalação 3, todas as outras instalações usarão o valor de configuração padrão no nível da conta.
| FacilityId | CompanyId | AccountId | SettingValue |
|------------|-----------|-----------|--------------|
| 3 | (null) | 1 | 6 |
Quero criar uma junção entre eles para obter a configuração mais específica para cada locatário. Mais específico é definido como o Setting
registro que corresponde ao Tenant
's FacilityId
é mais específico do que uma correspondência em CompanyId
que é mais específica do que uma correspondência em AccountId
e, finalmente, se nenhuma correspondência for encontrada, use a configuração que tem NULL
para todos os 3 valores.
Não quero usar o PIVOT
recurso, pois o código usa Entity Framework e LINQ e não há LINQ to SQL para PIVOT
. Basicamente, precisa de SQL simples para o qual você possa criar uma visão ... para que não haja tabelas temporárias, etc. Não procurando uma solução de proc armazenada, se possível.
Mesa:Settings
| FacilityId | CompanyId | AccountId | SettingValue |
|------------|-----------|-----------|--------------|
| 1 | 1 | 1 | 5 |
| (null) | 2 | 2 | 7 |
| (null) | 1 | 1 | 4 |
| (null) | (null) | 2 | 6 |
| (null) | (null) | 1 | 3 |
| (null) | (null) | (null) | 2 |
Mesa:Tenants
| FacilityId | CompanyId | AccountId |
|------------|-----------|-----------|
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
Então junte-se a eles teria esta saída desejada:
| FacilityId | CompanyId | AccountId | SettingValue |
|------------|-----------|-----------|--------------|
| 1 | 1 | 1 | 5 |
| 2 | 2 | 2 | 7 | --> this account would match to a setting value of 6 or 7, but the 7 value matches more specifically
| 3 | 3 | 3 | 2 | --> there is no match on Facility, Company, or Account so match to all nulls.
No código, estou fazendo o seguinte para obter o mais específico Setting
para um determinado Tenant
, mas agora preciso fazer isso para um grande conjunto de Tenant
dados e, portanto, quero fazê-lo por um SQL Join. Para aqueles que não estão familiarizados com LINQ, o double pipe( ||
) é equivalente a OR
.
private SettingViewModel GetSettingBy(string strKey)
{
var allSettings = GetAllSettings();
var settingQuery = allSettings.Where(x => x.SettingKey == strKey);
if (_accountCompanyFacilityViewModel.AccountId.HasValue)
{
settingQuery = settingQuery.Where(x => (x.AccountId == _accountCompanyFacilityViewModel.AccountId || x.AccountId == null));
}
if (_accountCompanyFacilityViewModel.CompanyId.HasValue)
{
settingQuery = settingQuery.Where(x => (x.CompanyId == _accountCompanyFacilityViewModel.CompanyId || x.CompanyId == null));
}
if (_accountCompanyFacilityViewModel.FacilityId.HasValue)
{
settingQuery = settingQuery.Where(x => (x.FacilityId == _accountCompanyFacilityViewModel.FacilityId || x.FacilityId == null));
}
var setting = settingQuery
.OrderByDescending(x => x.FacilityId)
.ThenByDescending(x => x.CompanyId)
.ThenByDescending(x => x.AccountId)
.FirstOrDefault();
return setting;
}
Aqui está o SQL Fiddle para a resposta
Obrigado pela ótima configuração de dados. Aqui está uma maneira de obter esses acertos no SQL. Como Aaron mencionou, isso pode ser um CTE sem variáveis.