ASP.NET Core Linq Compare Id and Sum value - sql

I have a problem and unfortunately can not find the solution!
This is my database:
enter image description here
and I would like to store all PaymentSum(double) [PaymentInformation] in the Total (double) [Document].
This is the SQL statement:
Select SUM(PaymentSum)
from PaymentInformations
where DocumentId = 1;
I have tried this, but without success:
// POST: api/PaymentInformations
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost("new/{eId}")]
public async Task<ActionResult<PaymentInformation>> PostpaymentInformations(long eId, PaymentInformation paymentInformation)
{
Document document = await _context.Documents.FindAsync(eId);
document.Total = _context.PaymentInformations
.Where(b => b.Document.Id == eId)
.Sum(a => a.PaymentSum);
//document.Total = _context.PaymentInformations.FromSqlRaw("Select SUM(PaymentSum) from PaymentInformations where DocumentId = {0}",eId).FirstOrDefault();
foreach (var item in _context.PaymentInformations)
{
System.Console.WriteLine(item.PaymentSum);
System.Console.WriteLine(item.DocumentId);
}
_context.PaymentInformations.Add(paymentInformation);
document.addPaymentInformation(paymentInformation);
await _context.SaveChangesAsync();
return CreatedAtAction("GetpaymentInformations", new { id = paymentInformation.Id }, paymentInformation);
}
I hope someone can help me.
Thank you!!

It looks like you are setting document.Total correctly, are you perhaps overriding the Total value when you call document.addPaymentInformation(paymentInformation) further down?

I set an breakpoint and it has shown that the id matches
enter image description here
transfer without success
enter image description here

public void addPaymentInformation(PaymentInformation paymentInformation)
{
if (PaymentInformations == null)
{
PaymentInformations = new List<PaymentInformation>();
}
paymentInformation.Document = this;
PaymentInformations.Add(paymentInformation);
}

Related

How to fill a Mock<DbSet> in Nunit with Moq?

I am trying to fill a mock dbset with a testentity but I only get exception after exception. I am very new to Nunit testing and haven't really got the hang of it. I am trying to test a simple delete method in my repository, here is the code for the method:
public async Task DeleteQuestion(Question questionToRemove)
{
if (questionToRemove is not null)
{
var questionsAnswers = await _context.Answers.Where(a => a.Question == questionToRemove).ToListAsync();
foreach (Answer a in questionsAnswers)
{
_context.Answers.Remove(a);
await _context.SaveChangesAsync();
}
_context.Questions.Remove(questionToRemove);
await _context.SaveChangesAsync();
var questions = await _context.Questions.Where(q => q.Quiz == questionToRemove.Quiz).ToListAsync();
int order = 1;
foreach (Question question in questions)
{
question.QuestionOrderId = order;
await _context.SaveChangesAsync();
order++;
}
}
}
And here is the test that I have written:
public async Task DeleteQuestionFunction()
{
//Arrange
Question testQuestion = new Question { QuestionId = 1, QuestionText = "Test" };
Answer testAnswer = new Answer { Question = testQuestion, AnswerId = 1, AnswerText = "TestAnswer" };
_appDBContextMock.SetupAdd(x => x.Questions.Add(testQuestion));
_appDBContextMock.SetupAdd(x => x.Answers.Add(testAnswer));
//Act
var questionListcomponent = new QuestionListComponent();
questionListcomponent.DeleteQuestion(testQuestion);
var testresult = await _questionRepositoryMock.Object.GetQuestionById(testQuestion.QuestionId);
//Assert
Assert.That(testresult, Is.Null);
}
When I only used the Setup method I got this exception:
System.NotSupportedException : Unsupported expression: x =>
x.Questions Non-overridable members (here: AppDbContext.get_Questions)
may not be used in setup / verification expressions.
and right now with the SetupAdd function I get this exception:
System.ArgumentException : Can not instantiate proxy of class:
TietoQuiz.Models.DbContexts.AppDbContext. Could not find a
parameterless constructor. (Parameter 'constructorArguments')
I think my problem is that I don't know how to set up a mock dbset properly. I tried to Google, but I found so many different ways and so many comments saying "that is not recommended/ the wrong way"! It is very confusing for a newbie, so I hope someone here can help!
If you want to write a test by using a context, you must create your own context and verify the data after running it. You cannot use mocks with non overridable methods.
You must use a temporary file to create this context not to change your production database.

Serenity Form Default Values

How can I get Max value from table Id field based on a lookup filter in grid?
I have a grid which shows records from a table customer and a lookup filter with different locations. I want to set the Id field in the new form with the Max value from Customers in the Location lookup filter.
I can set the Id field to a static value like 99. But how can I set it to the max value of the customer table? My code below:
#Serenity.Decorators.registerClass()
export class UtentesGrid extends Serenity.EntityGrid<UtentesRow, any> {
protected getColumnsKey() { return 'IpssDB.Utentes'; }
protected getDialogType() { return UtentesDialog; }
protected getIdProperty() { return UtentesRow.idProperty; }
protected getInsertPermission() { return UtentesRow.insertPermission; }
protected getLocalTextPrefix() { return UtentesRow.localTextPrefix; }
protected getService() { return UtentesService.baseUrl; }
constructor(container: JQuery) {
super(container);
}
protected addButtonClick() {
this.editItem(<IpssDB.UtentesRow>{
Codigo: 99
});
}
}
Also is there an event, on the server side (endpoint maybe), that gets called when the add button is clicked and which can allow me to execute c# code? This would give more "freedom" to scan database as I please.
PS:
I managed to solve the problem like this:
Built a Helper:
public static GetUtenteNextNumberResponse GetUtenteNextNumber(IDbConnection connection, GetUtenteNextNumberRequest request)
{
var min = connection.Query<string>(new SqlQuery()
.From("Locais")
.Select("UtenteCodMin")
.Where("Codigo = " + request.Local))
.FirstOrDefault();
var minN = (string.IsNullOrEmpty(min) ? 0 : int.Parse(min));
var minCod = connection.Query<string>(new SqlQuery()
.From("Utentes")
.Select("Codigo")
.Where("Codigo >= " + minN ))
.FirstOrDefault();
var response = new GetUtenteNextNumberResponse();
var n = 0;
response.Number = minCod == null ||
!int.TryParse(minCod, out n) ? minN + 1 : n + 1;
return response;
}
And in the Grid.ts:
protected addButtonClick() {
var eq = this.view.params.EqualityFilter;
var local = 0
local = eq ? eq.Local : 0;
var ultCod = 0;
IPSS.IpssDB.UtentesService.GetUtenteNextNumber({
Local: local,
User: ''
}, response => {
this.editItem(<IpssDB.UtentesRow>{
Codigo: response.Number,
Local: eq ? eq.Local : null
});
});
}
Now the problem is the new form assumes that I am editing a record and not creating a new one and the button "Save" appears as "Update". I suppose it is because I am changing the key field.
Is there a way to overcome this? Or is there another way to go?
If there was an event or endpoint called when the Add new button in grid is clicked, which allowed to return the entity with default values, that would be perfect.
Problem solved!
I was trying to intercept the wrong event. The event i should be intercepting, but didn't know about, was loadEntity and not afterLoadEntity.
So i kept the helper with no change and just replaced the 'UtentesDialog.ts' code like this:
"UtentesDialog.ts"
protected loadEntity(data) {
super.loadEntity(data);
var local = 0;
local = data.Local;
if (this.isNew())
this.getNextNumber(local);
}
private getNextNumber(local) {
IPSS.IpssDB.UtentesService.GetUtenteNextNumber({
Local: local,
User: ''
}, response => {
this.form.Codigo.value = response.Number;
});
};
I also had to keep the addButtonClick in the 'UtentesGrid.ts' in order to obtain the Local value so i could get it in the Dialog form. Otherwise i wouldn't be able to get the value of Local filter (maybe there is another way, i don't know).
"UtentesGrid.ts"
protected addButtonClick() {
var eq = this.view.params.EqualityFilter;
var local = 0
local = eq ? eq.Local : 0;
this.editItem(<IpssDB.UtentesRow>{
//Codigo: ultCod,
Local: eq ? eq.Local : null
});
}

Wit.ai How to Get an whole sentence in an entity

I would like to store an entire sentence an user said and store it.
This his how I did but I can't get the sentence from A to Z an an whole entity, just few parts knows as "number", "location", ....
merge(request) {
return new Promise(function(resolve, reject) {
var entities = request.entities;
var context = request.context;
var message = request.message;
var sessionId = request.sessionId;
var intent = firstEntityValue(entities, 'intent');
if (intent == "write_free_text") {
context.free_text = request["text"];
}
if (intent == "choose_city") {
var city = firstEntityValue(entities, 'location');
context.city = city;
}
return resolve(context);
});
}
How can I do that and store the whole sentence with merge function ? Thank you
If you want the whole sentence, maybe you don't needs a entity, just get the message sent:
// Merge action
function merge(request) {
context.freetext = request["text"];
return context;
}
Bot: https://wit.ai/Godoy/bottest/stories/4da2840f-513e-42ed-a494-c5516c07242e
Fiddle with code: https://wit-ai.github.io/witty-fiddle/?id=e4c16a624c87d37f9c0c29d8299ca5fc
if you want to get the whole phrase, use the wit/phrase_to_translate built-in entity
a snapshot of the uunderstanding tab
you just have to train the bot, once or twice.
It will pick up all the free text later.

send parameter to windows azure mobile server script in c# for Windows 8 Store app

I modified the "Read" operation on my Windows Azure Mobile Services Preview table (named "Item") as follows:
Javascript:
function read(query, user, request)
{
var howRead;
if(howRead == "unique")
{
var sqlUnique = "SELECT DISTINCT ? FROM Item WHERE qProjectCode = ?";
mssql.query(sqlUnique)
request.execute();
}
else if (howRead == "column")
{
var sqlColumn = "SELECT ? FROM Item WHERE qProjectCode = ?";
mssql.query(sqlColumn)
request.execute();
}
else if (howRead == "all")
{
var sqlAll = "SELECT * FROM Item WHERE qProjectCode = ?";
mssql.query(sqlAll)
request.execute();
}
}
This simply species when I want a unique list of a single column's values returned, all items in a single column, or all columns, respectively, all while limiting the read to those records with a given project code.
Right now, this works in C#, but scans the entire table (with other project codes) and always returns all columns. This is inherently inefficient.
c#
var client = new MobileServiceClient("[https path", "[key]");
var table = client.GetTable<Item>();
var query1 = table.Where(w => w.QProjectCode == qgv.projCode && w.QRecord == (int)lbRecord.Items[uStartRecordIndex]);
var query1Enum = await query1.ToEnumerableAsync();
foreach (var i in query1Enum)
{
// process data
}
How do I alter the c# code to deal with the Javascript code? Feel free to critique the overall approach, since I am not a great programmer and can always use advice!
Thanks
A few things:
In your server code, the mssql calls are not doing anything (useful). If you want to get their results, you need to pass a callback (the call is asynchronous) to it.
Most of your scenarios can be accomplished at the client side. The only for which you'll need server code is the one with the DISTINCT modifier.
For that scenario, you'll need to pass a custom parameter to the server script. You can use the WithParameters method in the MobileServiceTableQuery<T> object to define parameters to pass to the service.
Assuming this data class:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Other { get; set; }
public string ProjectCode { get; set; }
}
The code below can be used to accomplish the scenarios 2 and 3 at the client side only (no script needed at the server side). The other one will need some script, which I'll cover later.
Task<IEnumerable<string>> ReadingByColumn(IMobileServiceTable<Item> table, string projectCode)
{
return table
.Where(i => i.ProjectCode == projectCode)
.Select(i => i.Name)
.ToEnumerableAsync();
}
Task<IEnumerable<Item>> ReadingAll(IMobileServiceTable<Item> table, string projectCode)
{
return table.Where(i => i.ProjectCode == projectCode).ToEnumerableAsync();
}
Task<IEnumerable<string>> ReadingByColumnUnique(IMobileServiceTable<Item> table, string projectCode)
{
var dict = new Dictionary<string, string>
{
{ "howRead", "unique" },
{ "projectCode", projectCode },
{ "column", "Name" },
};
return table
.Select(i => i.Name)
.WithParameters(dict)
.ToEnumerableAsync();
}
Now, to support the last method (which takes the parameters, we'll need to do this on the server script:
function read(query, user, request)
{
var howRead = request.parameters.howRead;
if (howRead) {
if (howRead === 'unique') {
var column = request.parameters.column; // WARNING: CHECK FOR SQL INJECTION HERE!!! DO NOT USE THIS IN PRODUCTION!!!
var sqlUnique = 'SELECT DISTINCT ' + column + ' FROM Item WHERE ProjectCode = ?';
mssql.query(sqlUnique, [request.parameters.projectCode], {
success: function(distinctColumns) {
var results = distinctColumns.map(function(item) {
var result = [];
result[column] = item; // mapping to the object shape
return result;
});
request.respond(statusCodes.OK, results);
}
});
} else {
request.respond(statusCodes.BAD_REQUEST, {error: 'Script does not support option ' + howRead});
}
} else {
// no server-side action needed
request.execute();
}
}

EntityFramework, Insert if not exist, otherwise update

I'm having a Entity-Set Countries, reflecting a database table '<'char(2),char(3),nvarchar(50> in my database.
Im having a parser that returns a Country[] array of parsed countries, and is having issues with getting it updated in the right way. What i want is: Take the array of countries, for those countries not already in the database insert them, and those existing update if any fields is different. How can this be done?
void Method(object sender, DocumentLoadedEvent e)
{
var data = e.ParsedData as Country[];
using(var db = new DataContractEntities)
{
//Code missing
}
}
I was thinking something like
for(var c in data.Except(db.Countries)) but it wount work as it compares on wronge fields.
Hope anyone have had this issues before, and have a solution for me. If i cant use the Country object and insert/update an array of them easy, i dont see much benefict of using the framework, as from performers i think its faster to write a custom sql script that inserts them instead of ect checking if an country is already in the database before inserting?
Solution
See answer of post instead.
I added override equals to my country class:
public partial class Country
{
public override bool Equals(object obj)
{
if (obj is Country)
{
var country = obj as Country;
return this.CountryTreeLetter.Equals(country.CountryTreeLetter);
}
return false;
}
public override int GetHashCode()
{
int hash = 13;
hash = hash * 7 + (int)CountryTreeLetter[0];
hash = hash * 7 + (int)CountryTreeLetter[1];
hash = hash * 7 + (int)CountryTreeLetter[2];
return hash;
}
}
and then did:
var data = e.ParsedData as Country[];
using (var db = new entities())
{
foreach (var item in data.Except(db.Countries))
{
db.AddToCountries(item);
}
db.SaveChanges();
}
I would do it straightforward:
void Method(object sender, DocumentLoadedEvent e)
{
var data = e.ParsedData as Country[];
using(var db = new DataContractEntities)
{
foreach(var country in data)
{
var countryInDb = db.Countries
.Where(c => c.Name == country.Name) // or whatever your key is
.SingleOrDefault();
if (countryInDb != null)
db.Countries.ApplyCurrentValues(country);
else
db.Countries.AddObject(country);
}
db.SaveChanges();
}
}
I don't know how often your application must run this or how many countries your world has. But I have the feeling that this is nothing where you must think about sophisticated performance optimizations.
Edit
Alternative approach which would issue only one query:
void Method(object sender, DocumentLoadedEvent e)
{
var data = e.ParsedData as Country[];
using(var db = new DataContractEntities)
{
var names = data.Select(c => c.Name);
var countriesInDb = db.Countries
.Where(c => names.Contains(c.Name))
.ToList(); // single DB query
foreach(var country in data)
{
var countryInDb = countriesInDb
.SingleOrDefault(c => c.Name == country.Name); // runs in memory
if (countryInDb != null)
db.Countries.ApplyCurrentValues(country);
else
db.Countries.AddObject(country);
}
db.SaveChanges();
}
}
The modern form, using later EF versions would be:
context.Entry(record).State = (AlreadyExists ? EntityState.Modified : EntityState.Added);
context.SaveChanges();
AlreadyExists can come from checking the key or by querying the database to see whether the item already exists there.
You can implement your own IEqualityComparer<Country> and pass that to the Except() method. Assuming your Country object has Id and Name properties, one example of that implementation could look like this:
public class CountryComparer : IEqualityComparer<Country>
{
public bool Equals(Country x, Country y)
{
return x.Name.Equals(y.Name) && (x.Id == y.Id);
}
public int GetHashCode(Country obj)
{
return string.Format("{0}{1}", obj.Id, obj.Name).GetHashCode();
}
}
and use it as
data.Countries.Except<Country>(db, new CountryComparer());
Although, in your case it looks like you just need to extract new objects, you can use var newCountries = data.Where(c => c.Id == Guid.Empty); if your Id is Guid.
The best way is to inspect the Country.EntityState property and take actions from there regarding on value (Detached, Modified, Added, etc.)
You need to provide more information on what your data collection contains i.e. are the Country objects retrieved from a database through the entityframework, in which case their context can be tracked, or are you generating them using some other way.
I am not sure this will be the best solution but I think you have to get all countries from DB then check it with your parsed data
void Method(object sender, DocumentLoadedEvent e)
{
var data = e.ParsedData as Country[];
using(var db = new DataContractEntities)
{
List<Country> mycountries = db.Countries.ToList();
foreach(var PC in data)
{
if(mycountries.Any( C => C.Name==PC.Name ))
{
var country = mycountries.Any( C => C.Name==PC.Name );
//Update it here
}
else
{
var newcountry = Country.CreateCountry(PC.Name);//you must provide all required parameters
newcountry.Name = PC.Name;
db.AddToCountries(newcountry)
}
}
db.SaveChanges();
}
}