I have a ef-core + sql application with a model named "indicator". It has a ConcurrencyToken set to property "TimeStampUpdated".
In a long running task I read all indicators that must be marked for repeat with code:
var indicatorsToRepeat = await careOrganisationMessagingDbContext.Indicators
.Where(ind => ind.StateRepeat == true &&
ind.TimestampRepeat != null &&
EF.Functions.DateDiffSecond(ind.TimestampRepeat, timeStampNow) >= 0)
.ToListAsync();
if (indicatorsToRepeat != null && indicatorsToRepeat.Any())
{
foreach (Indicator indicator in indicatorsToRepeat)
{
indicator.MustRepeatNow = true;
indicator.TimestampRepeat = DateTime.UtcNow.AddSeconds((int)indicator.RepeatInterval);
}
try
{
await careOrganisationMessagingDbContext.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
// Do nothing
}
}
This task runs the repeat detection every 2 seconds and never changes "TimeStampUpdated". In potention one or more of the list of "indicatorsToRepeat" could be outdated by the shoot and forget tasks that do update indicators "State" as well as "TimeStampUpdated".
I'm not interested in detecting if indicator.DetectMustRepeatNow() saving fails. The Update must overrule and detectRepeats may not overwrite changes made by Update tasks. To achieve this I first imagined sql query with Where clause including "TimeStampUpdate" matching the old value. But this is not possible in ef-core. So I decided to use the ConcurrencyToken for "TimeStampUpdated". So update would fail if the value changed.
The real question:
I was wondering what would happen if I have 10 indicators to savechanges to where the third could not be updated due to concurrency (TimeStampUpdated changed between read and save).
Would the others (1..2 and 4..10) be updated or does the exception occure right after the third? I red this article below among others but cannot find the answer.
How to update row with concurrency control using EF Core?
Thanks in advance for answering my question,
Edwin
I am using entity framework core and have simple table structure where system has many logs, but for my certain functionality I want to have last child of that collection so i tried:
Models.Entities.System system = await Context.Systems
.Include(log => log.MaintenanceLogs)
.FirstOrDefaultAsync(system=> system.Id == system);
But as i know I can not add
.Include(log => log.MaintenanceLogs).Last()
Well it will not work, I could create manual query and get what I want, but that is not the point.
Also I can get all logs and get last after query materializes but still there can be whole lot of that logs db records and I need only last so why waste resources.
Reason is that I need to get one value from last log and base on that value update system ( of course all in transaction ).
Can it be done ?
Can you do
Models.Entities.MaintenanceLog log = await Context.MaintenanceLogs
.Include(log => log.System)
.LastOrDefaultAsync(log => log.System.Id == system);
instead? You know, switch it around.
This would only fetch a last entry in MaintenanceLogs table where the System.Id is equal to the value of system variable.
I need to find New Hires that have been entered into Success Factors and will be starting in the future via OData.
The following C# based query is what I'm using:
DateTime tomorrow = DateTime.UtcNow.AddDays(1);
var newHires = EmpEmployment
.Expand("userNav")
.Where (e => e.startDate >= tomorrow);
The above query returns staff who have a startDate in the future however the User expansion does not find any matching entries and is null.
The issue appears to be that the User table is only populated with entries for the person when the start date is reached. This is a problem because I want to create them in other systems in advance.
Does anyone know if this is normal or thoughts around how I can obtain details like firstname, lastname of future employees who have been entered in the system?
You are trying to use EmpEmployment entity from Employee Central. The required date could be retrieved from RCM (Recruitment Management).
There is no clear answer to your question because customizing depends on the project; you should ask functional consultant responsible for EC what the way to get New hires startDate.
I am trying to use LINQ in C# to perform a SQL query which selects multiple records based on a complex query.
I have a List of Person classes that have the following members that i want to search by:
First Name and City.
Normally in SQL I would iterate over this List and generate the following where statement
Where (Name="Name1" and City="City1") or (Name="Name2" and City="City2") or ...
I am wondering how I can achieve a similar result using LINQ.
I could do this using multiple queries but I want to use less queries due to the latency of the network and to let the database self optimize. The List will contain no more than 100 items at any time.
EDIT
As stated in the below comments the Person class was just an example to try and keep things simple. I will try and go into full detail and explain what I am trying to accomplish and see if you can help me or provide a better solution.
I have 2 database table of interest
Components
Placements
Components contains 8 fields plus an ComponentID. Every component should be unique.
Placements contains a list of fields plus a FK back to Components. There will be several Placements referencing one Component record in the database.
In C# I want to add Placements to the database with one transaction using a DataContext. I will be adding upto 1000 Placement rows to the database. If the Component does not exist I will have to create it. If it does exist I need to get its ComponentID so that I can link the Placement to the Component.
I have recently tried the following code:
The placementGroup has several members of which only 8 are needed to verify uniqueness. It should be noted that the 8 members listed below are unique between all of the objects stored in the list.
List<DBProductionComponent> existingComponents = context.DBProductionComponents.Where(dbc => placementGroup.Any(p =>
p.ComponentName == dbc.ComponentName &&
p.LotNumber == dbc.LotNumber &&
p.Manufacturer == dbc.Manufacturer &&
p.Package == dbc.PackageName &&
p.PartNumber == dbc.PartNumber &&
p.Supplier == dbc.Supplier &&
p.SupplierPartNumber == dbc.SupplierPartNumber &&
p.Value == dbc.Value
)).ToList();
But get the following error: "Local sequence cannot be used in LINQ to SQL implementations of queries except the Contains operator.
I have a Linq2SQL query running against a database provided by a third party. The main part of the query looks like this:
var valuationQuery =
from v in context.Valuations
where v.ModelId == QualifiedModelId.ModelId
&& v.QualifyModelId == QualifiedModelId.Qualifier
&& v.LanguageCode == QualifiedModelId.LanguageCode
&& v.Edition == Data.Meta.Edition.CurrentEdition.Date
&& v.RegDate == yearReg.RegistrationDate
&& v.ValTypeDescription == "Normal"
&& v.MileageBandID == MileageBand
When I loop around it with a foreach loop, it works or fails depending on the select at the end. When the select specifies all the fields like this...
select new
{
v.Value1,
v.Value2,
v.Value3,
... snip ...
v.Value14,
v.Value15,
v.ValueTypeID
};
... it works normally. When I do the following, the loop iterates the correct amount of times, but brings back the first record every time:
select v;
I want to be able to select all the fields without specifying the names in case the vendor adds more fields (they really are called "Value1" upto "Value15"), which means I can change one constant in my code and update the DBML and all the relevant code will lookup from the correct amount of fields. This query (and similar ones) are used in various places, so I'm looking for the least-effort in the future!
I have run SQL Profiler to ensure the query being run returns the correct results, and it does.
The foreach loop is this (the Convert's are due to the very badly designed database having very inconsistent datatypes):
foreach (var record in valuationQuery)
{
int CurrentValType = Convert.ToInt32(record.ValueTypeID);
string FieldName = "Value";
if (MPLower.MileagePointID >= 1 && MPLower.MileagePointID <= MaxMileagePoints)
{
FieldName = "Value" + MPLower.MileagePointID.ToString().Trim();
MPLower.MileagePointPounds[CurrentValType] = Convert.ToInt32(record.GetType().GetProperty(FieldName).GetValue(record, null));
}
if (MPHigher.MileagePointID >= 1 && MPHigher.MileagePointID <= MaxMileagePoints)
{
FieldName = "Value" + MPHigher.MileagePointID.ToString().Trim();
MPHigher.MileagePointPounds[CurrentValType] = Convert.ToInt32(record.GetType().GetProperty(FieldName).GetValue(record, null));
}
}
I'm new to C# (I've inherited some code), so I realise it's probably something stupid I've done or not done!! Please can anyone help?
Identity Maps
A common problem when using ORMs (ok, maybe not exactly common, but it can happen) is that a query which you expect to return distinct records ends up returning multiple copies of the same record. This is often caused by the ORM's Identity Map. Here's a quick overview of how it normally works.
The identity map is essentially an object cache, based on the primary key of each object.
When you ask the ORM for a record with a certain primary key, it'll check to see if the record already exists in the identity map. If it does already exist, it'll return the existing record.
This is usually pretty handy, but sometimes things go wrong. If two objects have the same primary key, or if you haven't specified what the primary keys are (forcing the ORM to guess), the identity map can't distinguish between them, and the first one will always be returned.
The moral of the story is, always double-check your primary keys if you are seeing multiple copies of the same record where you shouldn't be!
In this question, the code
select new
{
v.Value1,
v.Value2,
v.Value3,
... snip ...
v.Value14,
v.Value15,
v.ValueTypeID
};
works because you are using the select new{} projection to return an anonymous type, which bypasses the identity map.
select v
selects the objects directly, which does use the identity map, causing the problem you were seeing.