SQL Query Order of Operations - c#

It Friday. My brain is fried. This is very simple and I'm ashamed for asking this:
I simply want to query against my Event table (which has a non-null Start Time and nullable End time).However, given my unit test, I keep getting 2 records back (the 2:00 and the 4:00 records, not just the 2:00 as I'd expect)
SELECT
EventId,
TaskId,
MachineId,
LoginId,
EventStartTimeUtc,
EventEndTimeUtc,
OpCode,
UnitId,
PositionId,
WebId,
Comment,
MakereadyCount,
GrossCount,
NetCount,
PerpetualGross,
PerpetualNet,
PerpetualMakeready,
TaskState,
EventTypeId,
IsAutoEvent,
IsTransferred,
LastUpdatedTimeUtc
FROM Event
WHERE MachineId = #MachineId#
AND EventStartTimeUtc >= #StartTimeUtc#
AND (EventEndTimeUtc IS NULL
OR ((EventEndTimeUtc IS NOT NULL) AND EventEndTimeUtc <![CDATA[<=]]> #EndTimeUtc#))
[Test]
public void ShouldSelectEventsInRange()
{
//Arrange
TaskDto testTask = _testRepository.CreateTask(new TaskDto { TaskId = 1234567 }, true);
var machineId = ((ArtemisRepository)_testRepository).CreateMachine(123, "MR40SIM", "0V7", 200, 100, 555555); //Requires a 555555 down-task to exist in database
EventRecordDto result = _testRepository.CreateEvent(new EventRecordDto {TaskId = testTask.TaskId, MachineId = machineId, EventStartTimeUtc = new DateTime(2014, 4, 15, 1, 50, 0), OpCode = "100", MakereadyCount = 1752, GrossCount = 5660, NetCount = 2512, Comment = "Test Event", IsAutoEvent = false, IsTransferred = false});
EventRecordDto result2 = _testRepository.CreateEvent(new EventRecordDto {TaskId = testTask.TaskId, MachineId = machineId, EventStartTimeUtc = new DateTime(2014, 4, 15, 2, 0, 0), OpCode = "100", MakereadyCount = 1752, GrossCount = 5660, NetCount = 2512, Comment = "Test Event", IsAutoEvent = false, IsTransferred = false});
EventRecordDto result3 = _testRepository.CreateEvent(new EventRecordDto {TaskId = testTask.TaskId, MachineId = machineId, EventStartTimeUtc = new DateTime(2014, 4, 15, 4, 0, 0), OpCode = "100", MakereadyCount = 1752, GrossCount = 5660, NetCount = 2512, Comment = "Test Event", IsAutoEvent = false, IsTransferred = false});
//Act
var results = _testRepository.SelectEventsInRange(machineId, new DateTime(2014, 4, 15, 2, 0, 0), new DateTime(2014, 4, 15, 3, 59, 59));
//Assert
Assert.IsTrue(results.Count == 1, "{0} records came, instead of the 1 record expeted!", new object[] { results.Count });
Assert.IsTrue(results.Any(r => r.EventId == result2.EventId), "Expected Event (Id: {0}), Actual Event (ID: {1})", new object[] { result2.EventId, results[0].EventId});
}

The query asks for records where the EventStartTimeUtc is greater than or equal to 2:00, which both those records are, and where the EventEndTimeUtc is null, which they both are.
Did you mean EventStartTimeUtc where you have EventEndTimeUtc in the WHERE clause?

Related

Asserting in MSTEST that a collection OrderBy worked properly

Good morning. I am writing a unit test to validate that my API handler is sorting the collection properly. As you can see, it's mocked data and I intentionally created the test data out of order to test the OrderBy functionality. Once the handler returns the DTO collection, I want to validate that the "act" collection is in the same order as my "expectedDTO" collection. Here's the code:
[TestMethod]
public async Task GetByDay_ReturnsDtoList_WhenFound()
{
var testData = TestMethodData();
var expectedCalendarDto = ExpectedDto();
var testCalendar = testData;
var query = new GetCalendarByDaysQuery();
_mockCalendarRepo.Setup(m => m.GetItemsAsync(It.IsAny<ISpecification<CalendarDay>>(), null, null))
.ReturnsAsync(testCalendar);
var sut = new GetCalendarByDaysHandler(_mockCalendarRepo.Object, _mapper);
var act = await sut.HandleAsync(query);
Assert.IsNotNull(act);
Assert.IsInstanceOfType(act, typeof(IEnumerable<CalendarDto>));
Assert.AreEqual(expectedCalendarDto, act);
}
private GetItemsResult<IEnumerable<CalendarDay>> TestMethodData()
{
var testData = new GetItemsResult<IEnumerable<CalendarDay>>();
testData.ContinuationToken = null;
testData.Results = new List<CalendarDay>()
{
new CalendarDay { Id = "4-5-4|2021-04-01", FiscalYear = 2021, CalendarType = "4-5-4", Quarter = 2, Period = 4, CalendarDate = "2021-04-01", WeekOfYear = 13, DayOfYear = 61, WeekOfPeriod = 1 },
new CalendarDay { Id = "4-5-4|2021-08-01", FiscalYear = 2021, CalendarType = "4-5-4", Quarter = 3, Period = 8, CalendarDate = "2021-08-01", WeekOfYear = 24, DayOfYear = 121, WeekOfPeriod = 1 },
new CalendarDay { Id = "4-5-4|2021-01-01", FiscalYear = 2021, CalendarType = "4-5-4", Quarter = 1, Period = 1, CalendarDate = "2021-01-01", WeekOfYear = 1, DayOfYear = 1, WeekOfPeriod = 1 }
};
return testData;
}
private IEnumerable<CalendarDto> ExpectedDto()
{
var testDto = new List<CalendarDto>()
{
new CalendarDto { FiscalYear = 2021, CalendarType = "4-5-4", Quarter = 1, Period = 1, CalendarDate = "2021-01-01", WeekOfYear = 1, DayOfYear = 1, WeekOfPeriod = 1 },
new CalendarDto { FiscalYear = 2021, CalendarType = "4-5-4", Quarter = 2, Period = 4, CalendarDate = "2021-04-01", WeekOfYear = 13, DayOfYear = 61, WeekOfPeriod = 1 },
new CalendarDto { FiscalYear = 2021, CalendarType = "4-5-4", Quarter = 3, Period = 8, CalendarDate = "2021-08-01", WeekOfYear = 24, DayOfYear = 121, WeekOfPeriod = 1 }
};
return testDto;
}
Currently, in trying to compare the two collections, the test is failing saying that they aren't equal.
Assert.AreEqual failed. Expected:<System.Collections.Generic.List`1[cscentcalendar.infrastructure.DTOs.CalendarDto]>. Actual:<System.Collections.Generic.List`1[cscentcalendar.infrastructure.DTOs.CalendarDto]>.
Not sure what I'm doing wrong. Any assistance would be greatly appreciated.
I believe I solved the problem by using fluent assertion and adding the following line of code to test the two collections. Let me know if this is incorrect. Thanks again!
expectedCalendarDto.Should().BeEquivalentTo(act);

translate row_number over partition to C# linq

How to translate the following SQL query into C# Linq:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY StuffConditionId, StuffId ORDER BY StuffDayOfYear) AS RowNumber
FROM Stuff) rop
WHERE rop.RowNumber = 1;
Here is a partial dataset:
StuffId,StuffValue,StuffConditionId,StuffDayOfYear
2,9340,NULL,1
2,9340,NULL,2
2,9340,NULL,3
11,78,NULL,267
11,78,NULL,268
11,78,NULL,269
43,0,3,130
43,0,3,131
43,0,3,132
43,0,2,133
45,0,2,134
45,0,2,135
45,0,2,148
55,0,2,309
55,0,2,332
55,0,3,333
Answer Summary: The answer is to first build a in-memory list of stuffs, i.e. local list variable, then apply the LINQ query as shown in answer below.
Without some actual data I couldn't test this. But here's how this can be done, assuming stuff is your collection (aka table):
var firstInCollection = Stuff
.OrderBy(x => x.StuffDayOfYear)
.ToList() // Load in memory, then do groupby and select first due to EF Core
.GroupBy(x => new { condition = x.StuffConditionId, stuff = x.StuffId })
.Select(g => g.First());
Ok, I've tried this on a data table with a list of countries. Here are my results:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY SUBSTRING(CountryCode, 1, 1) ORDER BY CountryCode) AS RowNumber
FROM Lookup.Country) rop
WHERE rop.RowNumber = 1;
and got the following results in SQL
Then I used the following Linq statement. This is using Linq2SQL in LinqPad connected to my Microsoft SQL Database:
Countries
.OrderBy(c => c.CountryName)
.GroupBy(c => c.CountryName[0])
.Select(g => g.First())
And got the following result:
Which correlates with the SQL results.
Here's the example with your example data
void Main()
{
var stuffs = new []
{
new Stuff { StuffId = 2, StuffValue = 9340, StuffConditionId = null, StuffDayOfYear = 1 },
new Stuff { StuffId = 2, StuffValue = 9340, StuffConditionId = null, StuffDayOfYear = 2 },
new Stuff { StuffId = 2, StuffValue = 9340, StuffConditionId = null, StuffDayOfYear = 3 },
new Stuff { StuffId = 11, StuffValue = 78, StuffConditionId = null, StuffDayOfYear = 267 },
new Stuff { StuffId = 11, StuffValue = 78, StuffConditionId = null, StuffDayOfYear = 268 },
new Stuff { StuffId = 11, StuffValue = 78, StuffConditionId = null, StuffDayOfYear = 269 },
new Stuff { StuffId = 43, StuffValue = 0, StuffConditionId = 3, StuffDayOfYear = 130 },
new Stuff { StuffId = 43, StuffValue = 0, StuffConditionId = 3, StuffDayOfYear = 131 },
new Stuff { StuffId = 43, StuffValue = 0, StuffConditionId = 3, StuffDayOfYear = 132 },
new Stuff { StuffId = 43, StuffValue = 0, StuffConditionId = 2, StuffDayOfYear = 133 },
new Stuff { StuffId = 45, StuffValue = 0, StuffConditionId = 2, StuffDayOfYear = 134 },
new Stuff { StuffId = 45, StuffValue = 0, StuffConditionId = 2, StuffDayOfYear = 135 },
new Stuff { StuffId = 45, StuffValue = 0, StuffConditionId = 2, StuffDayOfYear = 148 },
new Stuff { StuffId = 55, StuffValue = 0, StuffConditionId = 2, StuffDayOfYear = 309 },
new Stuff { StuffId = 55, StuffValue = 0, StuffConditionId = 2, StuffDayOfYear = 332 },
new Stuff { StuffId = 55, StuffValue = 0, StuffConditionId = 3, StuffDayOfYear = 333 }
};
var firstInCollection = stuffs
.OrderBy(x => x.StuffDayOfYear)
.GroupBy(x => new { condition = x.StuffConditionId, stuff = x.StuffId })
.Select(g => g.First())
.Dump();
}
class Stuff
{
public int StuffId { get; set; }
public int StuffValue { get; set; }
public int? StuffConditionId { get; set; }
public int StuffDayOfYear { get; set; }
}
This results in the following:

Entity Framework error when adding a new entity to a DbSet

I have the following problem :
I created a class Actual. This is the mapping to the table:
ToTable("actuals");
HasKey(x => x.Id);
Property(x => x.Id).HasColumnName("actuals_sk");
...;
Property(x => x.PersonId).HasColumnName("actuals_by_sk");
Property(x => x.AssignmentId).HasColumnName("evaluation_task_id");
Property(x => x.JobCodeId).HasColumnName("job_cd_sk");
Property(x => x.ProjectId).HasColumnName("is_sk");
Now when I do a DbSet.Add(entity) where the entity is the actual instance, I keep getting the same error :
Cannot insert the value NULL into column 'person_sk', table 'aariworx_app.dbo.person'; column does not allow nulls. INSERT fails.
Now the strange thing is, that I provide all the necessary entities when mapping the properties.
Person person = new Person()
{ Id = 77,
Name = actualVM.Person.Name,
CreationDate = new DateTime(2014, 02, 04, 19, 53, 08, 000),
User = actualVM.Person.UserName,
Active = 1,
ContractHrs = 38,
ContractDays = Convert.ToDecimal("5,00"),
HoursFullDay = Convert.ToDecimal("7,60"),
HoursHalfDay = Convert.ToDecimal("3,80"),
MaxMoreHours = 80,
WarnMoreHours = 70,
Freelancer = 0,
AuthMethod = Model.Utils.AuthMethod.AD,
EmailSend = 0,
HourlyCost = 45 };
Assignment assignment = new Assignment() { Id = 3, Description = "Projectleiding", DTS = new DateTime(2006, 1, 5, 18, 30, 6, 000) };
JobCode jobCode = new JobCode() { Id = actualVM.JobCode.JobCodeId, Description = actualVM.JobCode.Description, CostCenter = 10, CostType = "F", LongDescription = "Ontwikkeling van de aariXa-website", Closed = 0, Date = new DateTime(2007, 5, 16, 2, 23, 12, 000) };
Project project = new Project() { Id = actualVM.Project.ProjectId, Description = actualVM.Project.Project, Date = new DateTime(2007, 5, 16, 2, 23, 12, 000) };
return new Actual()
{
Id = actualVM.Id,
...,
Assignment = assignment ,
AssignmentId = assignment.Id,
JobCode = jobCode,
JobCodeId = jobCode.Id,
Project = project,
ProjectId = project.Id,
Person = person,
PersonId = person.Id
};
So I don't know what is going wrong.
When I look at the queries that are being performed, there is an INSERT for person happening, which I don't need, since the person already exists.
Can anyone help me?
I noticed that when I do the savechanges to save my "actual" to the database, that the following query is also executed and I don't understand why :
INSERT [dbo].[person]([name], [user], [person_DTS], [pwd], [active_yn], [contract_hrs], [contract_days], [hours_full_day], [hours_half_day], [max_more_hours], [warn_more_hours], [freelancer_yn], [auth_method], [email_sent], [artikel_aarifact], [Uurkost])
VALUES (#0, #1, #2, NULL, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, NULL, #13)
SELECT [person_sk]
FROM [dbo].[person]
WHERE ##ROWCOUNT > 0 AND [person_sk] = scope_identity()
And since I'm passing the Id of the person, I don't see why the query should by using scope_identity()

LINQ Anonymous type - bypass Group By

I have LINQ sql (see below, thanks to Cameron ). I am trying to get a property (ItemCode) from class First without using that in Group by clause.
How do I do that?
Don't use First.ItemCode in group by but still want it in output by First.Begin, First.End order by decending.
public class First
{
public string Account;
public DateTime Begin;
public DateTime End;
public decimal Amount;
public string ItemCode;
}
public class Second
{
public string Account;
public DateTime Begin;
public DateTime End;
public decimal Amount;
}
List<First> firstAccount = new List<First>();
List<Second> secondAccount = new List<Second>();
firstAccount.Add(new First()
{
Account = "1234",
Begin = new DateTime(2014, 5, 13),
End = new DateTime(2014, 6, 12),
Amount = 9999,
ItemCode = "AAA"
});
firstAccount.Add(new First()
{
Account = "1234",
Begin = new DateTime(2014, 6, 13),
End = new DateTime(2014, 7, 7),
Amount = 1000,
ItemCode = "AAA"
});
firstAccount.Add(new First()
{
Account = "1234",
Begin = new DateTime(2014, 6, 13),
End = new DateTime(2014, 7, 14),
Amount = 0,
ItemCode = ""
});
firstAccount.Add(new First()
{
Account = "1234",
Begin = new DateTime(2014, 7, 7),
End = new DateTime(2014, 7, 14),
Amount = 1000,
ItemCode = "BBB"
});
secondAccount.Add(new Second()
{
Account = "1234",
Begin = new DateTime(2014, 5, 13),
End = new DateTime(2014, 6, 12),
Amount = 9999
});
secondAccount.Add(new Second()
{
Account = "1234",
Begin = new DateTime(2014, 6, 13),
End = new DateTime(2014, 7, 14),
Amount = 2000
});
var result = from account in (from first in firstAccount
join second in secondAccount
on first.Account equals second.Account
where
((first.Begin >= second.Begin && first.Begin <= second.Begin) &&
(first.End >= second.Begin && first.End <= second.End))
select new
{
first.Account,
second.Begin,
second.End,
first.Amount,
first.ItemCode
})
group account by new {account.Account, account.Begin, account.End }
into groupedAccounts
select new
{
groupedAccounts.Key.Account,
groupedAccounts.Key.Begin,
groupedAccounts.Key.End,
Sum = groupedAccounts.Sum(a => a.Amount)
};
One way to get the itemcode is to change the last select.
Add this line
Itemcode = String.Join(" ",groupedAccounts.Select(q=> q.ItemCode))
after Sum = groupedAccounts.Sum(a => a.Amount),
It should produce itemcode
foreach (var data in result)
{
Console.WriteLine(data.Account + " " + data.Itemcode);
}
Output
1234 AAA
1234 AAA

Dictionary of dates and values, finding value of max date per year in LINQ

Have a list like this:
01/01/2009, 120
04/01/2009, 121
30/12/2009, 520
01/01/2010, 100
04/01/2010, 101
31/12/2010, 540
I need to find the last value for each year, e.g. the result would be 520, 540?
var lastValues = records.OrderByDescending(r => r.Date)
.GroupBy(r => r.Date.Year)
.Select(g => g.First().Value);
class Program
{
static void Main()
{
var list = new[]
{
new { Date = new DateTime(2009, 1, 1), Value = 120 },
new { Date = new DateTime(2009, 4, 1), Value = 121 },
new { Date = new DateTime(2009, 12, 30), Value = 520 },
new { Date = new DateTime(2010, 1, 1), Value = 100 },
new { Date = new DateTime(2009, 4, 1), Value = 101 },
new { Date = new DateTime(2010, 12, 31), Value = 540 },
};
var result = list
.GroupBy(x => x.Date.Year)
.Select(g => new { Date = g.Key, MaxValue = g.Max(x => x.Value) });
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}

Categories