Here is the scenario...
Entities
public partial class **BenefitEnrolmentRule** : FullAuditedEntity, IMustHaveTenant
{
public BenefitEnrolmentRule()
{
DependentEnrolmentRules = new HashSet<DependentEnrolmentRule>();
}
[Key]
[Column(Order = 1)]
public int TenantId { get; set; }
[Key]
[Column("BenefitEnrolmentRuleId", Order = 2)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override int Id { get; set; }
public bool? TrapLate { get; set; }
[Required]
[Column(TypeName = "char(3)")]
public string GracePeriod { get; set; }
public byte[] RecordVersion { get; set; }
[InverseProperty("BenefitEnrolmentRule")]
public ICollection<DependentEnrolmentRule> DependentEnrolmentRules { get; set; }
}
}
public partial class **DependentEnrolmentRule** : Entity<short>, IMustHaveTenant
{
[Key]
[Column(Order = 1)]
public int TenantId { get; set; }
[Key]
[Column("BenefitEnrolmentRuleId", Order = 2)]
public int BenefitEnrolmentRuleId { get; set; }
[Key]
[Column("Dependent", Order = 3)]
public override short Id { get; set; }
[Column(TypeName = "char(3)")]
public string WaitingPeriod { get; set; }
public short StartDateCalc { get; set; }
public int TerminationAge { get; set; }
public short TerminationDateCalc { get; set; }
[ForeignKey("TenantId,BenefitEnrolmentRuleId")]
[InverseProperty("DependentEnrolmentRules")]
public BenefitEnrolmentRule BenefitEnrolmentRule { get; set; }
}
}
Dto....
public class **BenefitEnrolmentRuleDto**
{
BenefitEnrolmentRuleDto()
{
}
public int TenantId { get; set; }
public int Id { get; set; }
public int BenefitOptionId { get; set; }
public bool? TrapLate { get; set; }
[Required]
public string GracePeriod { get; set; }
public List<DependentEnrolmentRuleCreateInputDto> DependentEnrolmentRules { get; set; }
}
public class **DependentEnrolmentRuleCreateInputDto**
{
DependentEnrolmentRuleCreateInputDto()
{
}
public int TenantId { get; set; }
public int BenefitEnrolmentRuleId { get; set; }
public short Dependent { get; set; }
public string WaitingPeriod { get; set; }
public short StartDateCalc { get; set; }
public int TerminationAge { get; set; }
public short TerminationDateCalc { get; set; }
public bool isEligible { get; set; }
}
Update Method
public async Task UpdateBenefitEnrolmentRule(BenefitEnrolmentRuleDto input)
{
var benefitEnrolmentRule = await _benefitEnrolmentRepository.GetAll()
.Include(e => e.DependentEnrolmentRules)
.Where(e => e.Id == input.Id)
.SingleOrDefaultAsync();
ObjectMapper.Map(input, benefitEnrolmentRule);
await _benefitEnrolmentRepository.UpdateAsync(benefitEnrolmentRule);
}
Data from Angualar client (Dto)
BenefitEnrolmentRules={
"tenantId":2,
"id":32,
"benefitOptionId":0,
"trapLate":true,
"gracePeriod":"04D",
"dependentEnrolmentRules":[
{
"tenantId":2,
"benefitEnrolmentRuleId":32,
"dependent":1,
"waitingPeriod":"02D",
"startDateCalc":1,
"terminationAge":3,
"terminationDateCalc":1,
"isEligible":true
}
]
}
After this statement in the update method var benefitEnrolmentRule = await _benefitEnrolmentRepository.GetAll() .Include(e => e.DependentEnrolmentRules) .Where(e => e.Id == input.Id) .SingleOrDefaultAsync();
After this statement in the update method ObjectMapper.Map(input, benefitEnrolmentRule);
After last statement in update method await _benefitEnrolmentRepository.UpdateAsync(benefitEnrolmentRule);
Checking the profiler,
SQL profiler Statements exec sp_executesql N'SET NOCOUNT ON; UPDATE [BenefitEnrolmentRule] SET [CreationTime] = @p0, [CreatorUserId] = @p1, [DeleterUserId] = @p2, [DeletionTime] = @p3, [GracePeriod] = @p4, [IsDeleted] = @p5, [LastModificationTime] = @p6, [LastModifierUserId] = @p7, [TrapLate] = @p8 WHERE [TenantId] = @p9 AND [BenefitEnrolmentRuleId] = @p10 AND [RecordVersion] = @p11; SELECT [RecordVersion] FROM [BenefitEnrolmentRule] WHERE @@ROWCOUNT = 1 AND [TenantId] = @p9 AND [BenefitEnrolmentRuleId] = @p10; ',N'@p9 int,@p10 int,@p0 datetime2(7),@p1 bigint,@p2 bigint,@p3 datetime2(7),@p4 varchar(3),@p5 bit,@p6 datetime2(7),@p7 bigint,@p11 varbinary(8),@p8 bit',@p9=2,@p10=32,@p0='2018-10-23 15:49:20.5956672',@p1=3,@p2=NULL,@p3=NULL,@p4='04D',@p5=0,@p6='2018-10-23 16:52:05.2990144',@p7=3,@p11=0x000000000000568D,@p8=1
exec sp_executesql N'SET NOCOUNT ON; UPDATE [DependentEnrolmentRule] SET [TerminationAge] = @p0, [WaitingPeriod] = @p1 WHERE [TenantId] = @p2 AND [BenefitEnrolmentRuleId] = @p3 AND [Dependent] = @p4; SELECT @@ROWCOUNT; ',N'@p2 int,@p3 int,@p4 smallint,@p0 int,@p1 varchar(3)',@p2=2,@p3=32,@p4=1,@p0=3,@p1='02D'
exec sp_executesql N'SET NOCOUNT ON; **DELETE FROM [DependentEnrolmentRule] WHERE [TenantId] = @p0 AND [BenefitEnrolmentRuleId] = @p1 AND [Dependent] = @p2; SELECT @@ROWCOUNT; ',N'@p0 int,@p1 int,@p2 smallint',@p0=2,@p1=32,@p2=1 ** Problem: In UpdateAsync method, it is updating the DependentEnrolmentRule and next step is, it is deleting the same record (see sql profile statements). Not sure why.
One reason I was thinking is, In GetAll, BenefitEnrolmentRule object in the DependentEnrolmentRule (which is associated by FK) has data and after mapping with input object,BenefitEnrolmentRule in the DependentEnrolmentRule is null.
Please let me know how to fix this issue. I have posted all the code here. Really appreciate your help.
Thanks
Hi @ismcagdas,
It is a Dto class.. public List<BenefitOptionPlanOutputDto> BenefitOptionPlans { get; set; }
I am calling this from Angular this._classServiceProxy.getBenefitOption(this.benefitOptionId, moment()).subscribe(result => { this.benefitOption = result;
Hi @aaron,
Sorry, don't understand your message. Can you please explain a bit
Thanks
Hi @alper, I read the link before posting this message. I think this issue is not not related to muti-thread.
@aaron, if you look at the first line in the code posted in the orginal message is var benefitOption = await _benefitOptionRepository.GetAsync(input.Id);
Thanks
In the screenshot... BenefitEnrolmentRule is Null for Ruletype 0 BenefitEnrolmentRule is Not Null for Ruletype 2
In JSON, BenefitEnrolmentRule is Not Null for Ruletype 0 BenefitEnrolmentRule doesn't exist for Ruletype 2
After further investigation, the problem is not related to parsing or serialization. The problem is with JSON.stringify
I wrote it to console log to get the above JSON and it is wrong. console.log("benefit " + JSON.stringify(this.benefitOption))
Hi Guys,
I noticed the DTO object transfered to Angular has different map when it comes to child object.
Here is the issue.. API return dto BenefitOptionDto in quick watch
JSON on Angular.
{
"tenantId":2,
"id":4,
"classBenefitId":9,
"optionCode":"Option2",
"optionDescriptionEn":"Option2 Desc",
"isActive":true,
"benefitOptionPlans":[
{
"tenantId":2,
"id":4,
"benefitOptionId":4,
"ruleType":0,
"fromDate":"1900-01-01T05:00:00.000Z",
"ruleId":null
},
{
"benefitEnrolmentRule":{
"tenantId":2,
"id":2,
"trapLate":true,
"gracePeriod":"01M",
"dependentEnrolmentRules":[
{
"tenantId":2,
"benefitEnrolmentRuleId":2,
"dependent":1,
"waitingPeriod":"01D",
"startDateCalc":1,
"terminationAge":2,
"terminationDateCalc":1,
"terminationMonth":3,
"terminationDay":4,
"isEligible":false
}
],
"employmentRules":[
{
"tenantId":2,
"benefitEnrolmentRuleId":2,
"employmentType":1,
"minHours":3,
"frequency":1
}
],
"trappingRules":[
{
"tenantId":2,
"benefitEnrolmentRuleId":2,
"trappingCondition":2,
"nonEvidenceLimit":4,
"age":5,
"covBeforeDecision":1
}
]
},
"tenantId":2,
"id":5,
"benefitOptionId":4,
"ruleType":2,
"fromDate":"1900-01-01T05:00:00.000Z",
"ruleId":2
}
],
"isDefaultOption":false
}
If you compare both screen shot and JSON, "benefitEnrolmentRule" object should have been in the "ruleType":2 segment of benefitOptionPlans not "ruleType":0,.
This seems to be a big problem is parsing and serializing. Please help!
Thanks
Hi aaron,
Here are the definitions as requested.
DependentEnrolmentRuleOutputDto
public int TenantId { get; set; }
public int BenefitEnrolmentRuleId { get; set; }
public short Dependent { get; set; }
public string WaitingPeriod { get; set; }
public short StartDateCalc { get; set; }
public int TerminationAge { get; set; }
public short TerminationDateCalc { get; set; }
public bool isEligible { get; set; }
EmploymentRuleOutputDto
public int TenantId { get; set; }
public int BenefitEnrolmentRuleId { get; set; }
public short EmploymentType { get; set; }
public decimal MinHours { get; set; }
public short Frequency { get; set; }
TrappingRuleOutputDto
public int TenantId { get; set; }
public int BenefitEnrolmentRuleId { get; set; }
public short TrappingCondition { get; set; }
public short CovBeforeDecision { get; set; }
BenefitEnrolmentRuleId is propogated to the above entities from BenefitEnrolmentRuleOutputDto Id.
PS: It works if I changed the signature of the method (removed async Task) from public async Task BenefitOptionOutputDto GetBenefitOption(BenefitOptionGetInputDto input) to public BenefitOptionOutputDto GetBenefitOption(BenefitOptionGetInputDto input) I am not sure that it is the solution. It has to be a better way I guess.
Thanks for quick reply.
Hi aaron,
BenefitOptionOutputDto public int TenantId { get; set; } public long Id { get; set; } public string OptionCode { get; set; } public bool IsActive { get; set; } public List<BenefitOptionPlanOutputDto> BenefitOptionPlans { get; set; }
BenefitOptionPlanOutputDto public int TenantId { get; set; } public long Id { get; set; } public long BenefitOptionId { get; set; } public DateTime FromDate { get; set; } public short RuleType { get; set; } public int? RuleId { get; set; } public BenefitEnrolmentRuleOutputDto BenefitEnrolmentRule;
BenefitOptionPlanOutputDto is generic table we have where all the rules are attached. One of the rule is BenefitEnrolmentRuleOutputDto which is identfied by RuleType and RuleId. So there is no FK association defined between RuleId and BenefitEnrolmentRuleOutputDto.
BenefitEnrolmentRuleOutputDto public int TenantId { get; set; } public int Id { get; set; } public string GracePeriod { get; set; } public List<DependentEnrolmentRuleOutputDto> DependentEnrolmentRules { get; set; } public List<EmploymentRuleOutputDto> EmploymentRules { get; set; } public List<TrappingRuleOutputDto> TrappingRules { get; set; }
Hope this helps!
Thanks