Şimdi Film sayfasını açarsak kiracı2'nin sadece kiracısına ait filmleri görebildiğini göreceğiz .
Ancak bir filme oyuncu eklemeye çalıştığınızda tüm kişiler gösterilir.:

Bu veriler dinamik bir komut dosyası aracılığıyla komut dosyası tarafına beslenir.
Bu verileri yakın zamanda ele aldığımız Liste hizmetlerine yüklemiyor .
Bu açılır listeyi oluşturan arama komut dosyası PersonRow.cs'de tanımlanmıştır :
namespace MultiTenancy.MovieDB
{
[ConnectionKey("Default"), Module("MovieDB"), TableName("[mov].[Person]")]
[DisplayName("Person"), InstanceName("Person")]
[ReadPermission("Administration:General")]
[ModifyPermission("Administration:General")]
[LookupScript("MovieDB.Person")] // <-- This is the definition
public sealed class PersonRow : Row<PersonRow.RowFields>, IIdRow, INameRow, IMultiTenantRow
{
[DisplayName("Person Id"), Identity, IdProperty]
public int? PersonId
{
get => fields.PersonId[this];
set => fields.PersonId[this] = value;
}
Bazen verileri özelleştirmek için özel arama komut dosyaları kullanmamız gerekir.
Örneğin kuzey rüzgarı örneği TedarikçiCountryLookup .
Bu arama sınıfı RowLookupScript temel sınıfından türetilir . Bu durumda bu tür aramaları da halletmemiz gerekir.
Arama sorgusunu mevcut kiracıya göre filtrelememiz gerekir.
Daha sonra ele almamız gereken diğer arama komut dosyalarına hazırlanmak için yeni bir temel sınıf oluşturalım.
using Serenity;
using Serenity.Abstractions;
using Serenity.Data;
using Serenity.Web;
using System;
namespace MultiTenancy
{
public class MultiTenantRowLookupScript<TRow> :
RowLookupScript<TRow>
where TRow : class, IRow, IMultiTenantRow, new()
{
public ITwoLevelCache TwoLevelCache { get; }
public IUserAccessor UserAccessor { get; }
public MultiTenantRowLookupScript(ISqlConnections sqlConnections, ITwoLevelCache twoLevelCache, IUserAccessor userAccessor) : base(sqlConnections)
{
Expiration = TimeSpan.FromDays(-1);
TwoLevelCache = twoLevelCache ?? throw new ArgumentNullException(nameof(twoLevelCache));
UserAccessor = userAccessor ?? throw new ArgumentNullException(nameof(userAccessor));
}
protected override void PrepareQuery(SqlQuery query)
{
base.PrepareQuery(query);
AddTenantFilter(query);
}
protected void AddTenantFilter(SqlQuery query)
{
var r = new TRow();
query.Where(r.TenantIdField == UserAccessor.User.GetTenantId());
}
public override string GetScript()
{
return TwoLevelCache.GetLocalStoreOnly("MultiTenantLookup:" +
this.ScriptName + ":" +
UserAccessor.User.GetTenantId(),
TimeSpan.FromHours(1),
new TRow().GetFields().GenerationKey, () =>
{
return base.GetScript();
});
}
}
}
Bu, çok kiracılı arama komut dosyaları için temel sınıfımız olacaktır.
Önbelleğe almayı devre dışı bırakmak için ilk önce sona erme tarihini negatif bir zaman aralığına ayarladık. Bunu neden yapmak zorundayız? Çünkü dinamik komut dosyası yöneticisi, arama komut dosyalarını anahtarlarıyla önbelleğe alır. Ancak TenantId değerlerine dayalı bir arama komut dosyasının birden çok sürümüne sahip olacağız.
Önbelleğe almayı dinamik komut dosyası yöneticisi düzeyinde kapatacağız ve önbelleğe almayı GetScript yönteminde kendimiz halledeceğiz. GetScript yönteminde , arama betiğimizi oluşturan temel yöntemi çağırmak ve sonucunu TenantId içeren bir önbellek anahtarıyla önbelleğe almak için TwoLevelCache.GetLocalStoreOnly kullanıyoruz .
TwoLevelCache sınıfı hakkında daha fazla bilgi için ilgili bölüme bakın.
Hazırlık Sorgu yöntemini geçersiz kılarak , tıpkı liste hizmet işleyicilerinde yaptığımız gibi geçerli TenantId'ye göre bir filtre ekliyoruz .
Şimdi bu yeni temel sınıfı kullanarak TedarikçiCountryLookup adlı kuzey rüzgarı örnek aramasını nasıl uygulayacağımızı görelim :
namespace MultiTenancy.Northwind.Scripts
{
using Serenity.ComponentModel;
using Serenity.Data;
using Serenity.Web;
[LookupScript("Northwind.SupplierCountry")]
public class SupplierCountryLookup :
MultiTenantRowLookupScript<SupplierRow>
{
public SupplierCountryLookup(ISqlConnections sqlConnections, ITwoLevelCache twoLevelCache, IUserAccessor userAccessor) : base(sqlConnections)
{
IdField = TextField = "Country";
}
protected override void PrepareQuery(SqlQuery query)
{
var fld = SupplierRow.Fields;
query.Distinct(true)
.Select(fld.Country)
.Where(
new Criteria(fld.Country) != "" &
new Criteria(fld.Country).IsNotNull());
AddTenantFilter(query);
}
protected override void ApplyOrder(SqlQuery query)
{
}
}
}
AddTenantFilter yöntemini manuel olarak çağırdık , çünkü burada temel HazırlıkQuery yöntemini çağırmıyorduk (bu nedenle temel sınıf tarafından çağrılmayacak).
Satırlardaki Komut Dosyası Bildirimlerini Arama
Artık çözmemiz gereken bir sorunumuz daha var. Satırlardaki [LookupScript] özelliği.
Varsayılan olarak LookupScript, türe dayalı bir arama örneği oluşturur RowLookupScript<>. MultiTenantRowLookupScript<>Bu çok kiracılı satırlar için bunu olarak değiştirmemiz gerekiyor .
Kişi aramayı düzeltelim. PersonRow'da [LookupScript] niteliğini aşağıdaki gibi değiştirin .
[ConnectionKey("Default"), Module("MovieDB"), TableName("[mov].[Person]")]
[DisplayName("Person"), InstanceName("Person")]
[ReadPermission("Administration:General")]
[ModifyPermission("Administration:General")]
[LookupScript("MovieDB.Person", LookupType = typeof(MultiTenantRowLookupScript<>))]
public sealed class PersonRow : Row<PersonRow.RowFields>, IIdRow, INameRow, IMultiTenantRow
{
//...
Bunun Serenity 2.9.22+ gerektirdiğini unutmayın.
GenreRow satırı için de benzerini yapın (LookupType ekleyin) .
Artık MovieDB çoklu kiracılığı destekliyor.
Gözden kaçırdığım bazı aksaklıklar olabilir, varsa Serenity Github deposunda bildirin.