Excellent! That's what I was hoping it will work.
Then, I will use one of the DbContexts only to update database, not both will do that.
Shall I set "SetInitializer(null)" in the Module class, inside the module that I want it to just "READ" from the db and ot change any table structure? Or no need?
Regards Bilal
Great.
Assuming I have 2 business modules.
Module 1: Contains entities like Car, Driver, etc. (all detailed properties) Module 2: Requires an entity Car but not all of the properties maybe only Id, Name.
I could create 2 DB Contexts, one in each project. Also, I will have entity Car defined in 2 places, in the first module with all properties and in the second module with only Id and Name.
Module 1 will be responsible for creating the tables in DB in this case.
So, in this case, I have 2 BaseRepositories each targeting a different DbContext. However, same entity like Car will appear in 2 DbContext.
Going back to the source code you referred me to,:
var primaryKeyType = EntityHelper.GetPrimaryKeyType(entityTypeInfo.EntityType);
if (primaryKeyType == typeof(int))
{
var genericRepositoryType = autoRepositoryAttr.RepositoryInterface.MakeGenericType(entityTypeInfo.EntityType);
if (!iocManager.IsRegistered(genericRepositoryType))
{
var implType = autoRepositoryAttr.RepositoryImplementation.GetGenericArguments().Length == 1
? autoRepositoryAttr.RepositoryImplementation.MakeGenericType(entityTypeInfo.EntityType)
: autoRepositoryAttr.RepositoryImplementation.MakeGenericType(entityTypeInfo.DeclaringType, entityTypeInfo.EntityType);
iocManager.Register(
genericRepositoryType,
implType,
DependencyLifeStyle.Transient
);
}
}
This means that IRepository<Car> would map to EfRepository<Module1DbContext, Car, int>. So Module1RepositoryBase will be created based on EfRepository<Module1DbContext, Car, int>.
Now, in Module 2, given the code referenced above, we will have something similar: IRepository<Car> would map to EfRepository<Module3DbContext, Car, int>. So Module3RepositoryBase will be created based on EfRepository<Module2DbContext, Car, int>.
Now, in the code, how would it know which DbContext to use?
Thanks
Do you have a similar case in the framework where you needed to call the Database from the Razor View? I can at least follow the code and see the way you thought about it.
Thanks, Bilal
Hi, I am facing a big issue now with this design! I will paste the code here and tell you where the problem is.
I've highlighted in bold the method that I dunno how to proceed from now on. I followed the pattern you use in some of the classes to create a manager and using caching also.
I am stuck here and really appreciate your assistance.
Regards Bilal
public class HostEntityBase<TPrimaryKey> : FullAuditedEntity<TPrimaryKey>, IMayHaveTenant
{
public virtual int? TenantId { get; set; }
[Required]
[StringLength(HostEntityConsts.MaxLabelLength)]
public virtual string Label { get; protected set; }
public virtual string Notes { get; protected set; }
public virtual void UpdateLabel(string newLabel)
{
//Validate newLabel
Check.NotNull(newLabel, nameof(newLabel));
Label = newLabel;
}
public virtual void UpdateNotes(string newNotes)
{
Notes = newNotes;
}
}
public class HostEntityWithIntKeyBase : HostEntityBase<int>
{
}
public class ClothingSize : HostEntityWithIntKeyBase, IMayHaveTenant
{
/// <summary>
/// EF
/// </summary>
protected ClothingSize()
{
}
public static ClothingSize Create(string label, string notes = null)
{
var clothingSize = new ClothingSize();
clothingSize.UpdateLabel(label);
clothingSize.UpdateNotes(notes);
return clothingSize;
}
}
/// <summary>
/// Used to cache HostEntities
/// </summary>
public class HostEntityCacheItem
{
public const string CacheStoreName = "DrcHostEntities";
public List<HostEntityCacheItemSingle> Items { get; set; }
public HostEntityCacheItem()
{
Items = new List<HostEntityCacheItemSingle>();
}
}
public class HostEntityCacheItemSingle
{
public object Id { get; set; }
public string Label { get; set; }
public string Notes { get; set; }
}
public static class DrcCacheManagerExtensions
{
public static ITypedCache<string, HostEntityCacheItem> GetHostEntityCache(this ICacheManager cacheManager)
{
return cacheManager.GetCache<string, HostEntityCacheItem>(HostEntityCacheItem.CacheStoreName);
}
}
public class ReferenceDataManager<THostEntityBase> :
ReferenceDataManager<THostEntityBase, int>,
IReferenceDataManager<THostEntityBase>
where THostEntityBase : HostEntityBase<int>
{
public ReferenceDataManager(
ICacheManager cacheManager,
IRepository<THostEntityBase, int> repository,
IUnitOfWorkManager unitOfWorkManager,
string cacheName = null)
: base(
cacheManager,
repository,
unitOfWorkManager,
cacheName)
{
}
}
public class ReferenceDataManager<THostEntityBase, TPrimaryKey> :
IReferenceDataManager<THostEntityBase, TPrimaryKey>,
ISingletonDependency
where THostEntityBase : HostEntityBase<TPrimaryKey>
{
public string CacheName { get; private set; }
protected ICacheManager CacheManager { get; private set; }
protected IUnitOfWorkManager UnitOfWorkManager { get; private set; }
protected IRepository<THostEntityBase, TPrimaryKey> Repository { get; private set; }
public ReferenceDataManager(ICacheManager cacheManager,
IRepository<THostEntityBase, TPrimaryKey> repository,
IUnitOfWorkManager unitOfWorkManager,
string cacheName = null)
{
UnitOfWorkManager = unitOfWorkManager;
Repository = repository;
CacheManager = cacheManager;
CacheName = cacheName ?? GenerateDefaultCacheName();
}
public virtual async Task<IReadOnlyList<THostEntityBase>> GetAsync()
{
return (await GetListAsync());
}
}
**[UnitOfWork]
private async Task<List<THostEntityBase>> GetListAsync()
{
var entity = await GetListFromCacheAsync();
var instances = new List<THostEntityBase>();
foreach(HostEntityCacheItemSingle e in entity.Items)
{
instances.Add(new HostEntityBase<TPrimaryKey> { Id = } );
}
return instances;
}**
[UnitOfWork]
private async Task<HostEntityCacheItem> GetListFromCacheAsync()
{
return await CacheManager.GetHostEntityCache().GetAsync("0", async () =>
{
//Get a list from the database
var list = (await GetHostEntityFromDatabaseAsync());
var newItem = new HostEntityCacheItem();
foreach (var l in list)
{
newItem.Items.Add(new HostEntityCacheItemSingle { Id = l.Id, Label = l.Label, Notes = l.Notes });
}
return newItem;
});
}
[UnitOfWork]
protected async virtual Task<List<THostEntityBase>> GetHostEntityFromDatabaseAsync()
{
//Get THostEntityBase from host not any specific tenant
using (UnitOfWorkManager.Current.SetTenantId(null))
{
return await Repository
.GetAllListAsync();
}
}
Thanks a lot.
Hi,
I am currently using the framework with Angular js 1.x.
By default, the framework would generate Web API proxies for all those objects that implemented IAppService.
Therefore, I use the proxy on the client side to call any method defined on the ApplicationSevice layer using only DTOs.
Generally speaking, DTO is more or less a ViewModel.
HTH, Bilal
So, I would define an IDataLoader and DataLoader and then in my view, I Resolve this class and call that method on it? Or something else?
Thanks
Great. Thanks.
Is there a way to create Permissions by the Admin from the Web App? Currently, I create them inside .Core module.
Regards Bilal
Ok great. Thanks.
You are right, it depends. In my case, I am caching some reference data. However, this data might change, so I will invalidate the data once it changes. But as a manager, I only need a single instance from it, no need to have an instance every time it is being asked for.
Regards Bilal
Thanks, no need to explain it. I went through all the related classes and it makes perfect sense :)
Given the fact, the AbpDbContext could have an unknown number of IDbSet<T> ahead of time, this code is needed.
In my case, I just want to map IFoo<T> or IFoo<T,Z> to Foo<T> or Foo<T,Z>, so I use this code and it seems to be working fine.
private void RegisterForReferenceDataManager()
{
IocManager.RegisterIfNot(
typeof(IReferenceDataManager<,>),
typeof(ReferenceDataManager<,>),
DependencyLifeStyle.Singleton);
}
One question though, what's the recommendation to use Singleton or Transient? When will each be used?
In case I am registering the classes as above, do I still need to have Foo<T> implement ISingletonDependency? As I understand, this interface is used only when doing the below so that CW would know how to register an interface and implementation. Correct?
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());