Hi,
Don't see any shortcomings in your code.
I'have the same issue for one of my other entities with two many to many relations. One list got saved and the other does not! Check: [http://forum.aspnetboilerplate.com/viewtopic.php?f=5&t=2458&p=5695&hilit=many#p5695])
Perhaps hikalkan can help us out!
Hi,
what code do you use to actually add the objects?
Hi,
In your scenario it should be enough to define property public virtual ICollection<Country> Countries { get; set; } in Provider class and public virtual ICollection<Provider> Providers { get; set; } in Country class
EF will setup an extra link table by itsself and you're able to add many countries to provider and many providers to country just by adding them in the collection normally save them.
Former error got solved by adding ExtendedAuditLog to BIDbContext
I'm now capable of logging custommade errors in the same table without having to create new entity and appservice etc.
Thanks,
Hi,
I extended entity AuditLog:
public class ExtendedAuditLog : AuditLog,
{
public string Entity { get; set; }
public int EntityId { get; set; }
public Guid EntityGuid { get;}
}
This wil cause an inheritance situation in EF with discriminator field - works ok. But the AuditLogAppService is now broken :? with dep error: Can't create component 'Intertek.BI.Auditing.AuditLogAppService' as it has dependencies to be satisfied.
'Intertek.BI.Auditing.AuditLogAppService' is waiting for the following dependencies:
appservice code (only with changed entity auditlog > extendedauditlog)
[DisableAuditing]
[AbpAuthorize(AppPermissions.Pages_Administration_AuditLogs)]
public class AuditLogAppService : BIAppServiceBase, IAuditLogAppService
{
private readonly IRepository<ExtendedAuditLog, long> _auditLogRepository;
private readonly IRepository<User, long> _userRepository;
private readonly IAuditLogListExcelExporter _auditLogListExcelExporter;
public AuditLogAppService(IRepository<ExtendedAuditLog, long> auditLogRepository, IRepository<User, long> userRepository, IAuditLogListExcelExporter auditLogListExcelExporter)
{
_auditLogRepository = auditLogRepository;
_userRepository = userRepository;
_auditLogListExcelExporter = auditLogListExcelExporter;
}
public async Task<PagedResultOutput<AuditLogListDto>> GetAuditLogs(GetAuditLogsInput input)
{
var query = CreateAuditLogAndUsersQuery(input);
var resultCount = await query.CountAsync();
var results = await query
.AsNoTracking()
.OrderBy(input.Sorting)
.PageBy(input)
.ToListAsync();
var auditLogListDtos = ConvertToAuditLogListDtos(results);
return new PagedResultOutput<AuditLogListDto>(resultCount, auditLogListDtos);
}
public async Task<FileDto> GetAuditLogsToExcel(GetAuditLogsInput input)
{
var auditLogs = await CreateAuditLogAndUsersQuery(input)
.AsNoTracking()
.OrderByDescending(al => al.AuditLog.ExecutionTime)
.ToListAsync();
var auditLogListDtos = ConvertToAuditLogListDtos(auditLogs);
return _auditLogListExcelExporter.ExportToFile(auditLogListDtos);
}
private static List<AuditLogListDto> ConvertToAuditLogListDtos(List<AuditLogAndUser> results)
{
return results.Select(
result =>
{
var auditLogListDto = result.AuditLog.MapTo<AuditLogListDto>();
auditLogListDto.UserName = result.User == null ? null : result.User.UserName;
auditLogListDto.ServiceName = StripNameSpace(auditLogListDto.ServiceName);
return auditLogListDto;
}).ToList();
}
private IQueryable<AuditLogAndUser> CreateAuditLogAndUsersQuery(GetAuditLogsInput input)
{
var query = from auditLog in _auditLogRepository.GetAll()
join user in _userRepository.GetAll() on auditLog.UserId equals user.Id into userJoin
from joinedUser in userJoin.DefaultIfEmpty()
where auditLog.ExecutionTime >= input.StartDate && auditLog.ExecutionTime < input.EndDate
select new AuditLogAndUser {AuditLog = auditLog, User = joinedUser};
query = query
.WhereIf(!input.UserName.IsNullOrWhiteSpace(), item => item.User.UserName.Contains(input.UserName))
.WhereIf(!input.ServiceName.IsNullOrWhiteSpace(), item => item.AuditLog.ServiceName.Contains(input.ServiceName))
.WhereIf(!input.MethodName.IsNullOrWhiteSpace(), item => item.AuditLog.MethodName.Contains(input.MethodName))
.WhereIf(!input.BrowserInfo.IsNullOrWhiteSpace(), item => item.AuditLog.BrowserInfo.Contains(input.BrowserInfo))
.WhereIf(input.MinExecutionDuration.HasValue && input.MinExecutionDuration > 0, item => item.AuditLog.ExecutionDuration >= input.MinExecutionDuration.Value)
.WhereIf(input.MaxExecutionDuration.HasValue && input.MaxExecutionDuration < int.MaxValue, item => item.AuditLog.ExecutionDuration <= input.MaxExecutionDuration.Value)
.WhereIf(input.HasException == true, item => item.AuditLog.Exception != null && item.AuditLog.Exception != "")
.WhereIf(input.HasException == false, item => item.AuditLog.Exception == null || item.AuditLog.Exception == "");
return query;
}
private static string StripNameSpace(string serviceName)
{
if (serviceName.IsNullOrEmpty() || !serviceName.Contains("."))
{
return serviceName;
}
var lastDotIndex = serviceName.LastIndexOf('.');
return serviceName.Substring(lastDotIndex + 1);
}
public void SaveEventExcecutionResult(AuditLogEditDto input)
{
var auditLog = input.MapTo<ExtendedAuditLog>();
_auditLogRepository.Insert(auditLog);
}
}
Can I do something about that? Or should I reverse this and trying to change AuditlogProvider instead (which is nog quitte obvious to me yet).
I alway answer my own questions, it seems.. :mrgreen:
I came across this post concerning the same issue [ #143@9631572b-914f-48a0-b397-5fc4249f15fb ])
Hi,
What's the most efficient way to change auditlog entity with some extra fields? Tried to add a partial class but the initial class is not partial.
Should I extend it?
Thanks again,
Hi,
Way to go! Yes, we should not use entity objects in dto's and yes, you can add the Id of an entity in the definition of an entity like copied below. Then you can set the proper id yourself without the use of instances of the object, in this case report.
Furthermore, set the property Report to virtual when you want it to be lazy loaded!
public class Job : EntityBase
{
public int ReportId { get; set; }
public virtual Report Report { get; set; }
public string CronSchedule { get; set; }
public ReportOutputType OutputType { get; set; }
public DateTime LastRun { get; set; }
public bool Active { get; set; }
public string Destination { get; set; }
}
Hi,
Thanks for thinking with me :-) I'm currently testing a procedure with in I added ReportId property to Entity Job (definition in .core) and change the dto property report into reportId.
I'll update in a sec.
Hi,
public class CreateOrUpdateJobInput : IInputDto { [Required] public JobEditDto Job { get; set; } }
[AutoMapFrom(typeof(Job))] [AutoMapTo(typeof(Job))] public class JobEditDto : FullAuditedEntityDto { public Report Report { get; set; } public string CronSchedule { get; set; } public ReportOutputType OutputType { get; set; } public DateTime? LastRun { get; set; } public bool Active { get; set; } public string Destination { get; set; } }