how to make dbContext ExecuteSqlCommand work with new uncommitted entities - ef-code-first

Is there a way to make ExecuteSqlCommand work with new uncommitted entities.
using (var context = new EarthContext())
{
var country = new Country(){
Id = "ZZZ",
IsoCodeAlpha2 = "ZZ",
IsoCodeNumberic = 999
};
context.Countries.Add(country);
context.Database.ExecuteSqlCommand(
#"
INSERT INTO dbo.Location([Line1],[CountryId])
VALUES ('random line','ZZZ')
");
context.SaveChanges();
}
It gives a "The INSERT statement conflicted with the FOREIGN KEY constraint" exception because ExecuteSqlCommand executes before the new entities are committed.
*Code must run in one transaction i.e. I cannot commit changes before the ExecuteSqlCommand

As I know all sql queries called using context.Database.ExecuteSqlCommand are executed on different transaction than "common" context operation. Another point is that ExecuteSqlCommand is called immediately and all operations like context.Countries.Add(country); (all inserts, updates or deletes) are executed with context.SaveChanges();.
You should try with:
using (var context = new EarthContext())
{
var country = new Country(){
Id = "ZZZ",
IsoCodeAlpha2 = "ZZ",
IsoCodeNumberic = 999
};
context.Countries.Add(country);
context.SaveChanges(); // to commit country insertion
context.Database.ExecuteSqlCommand(
#"
INSERT INTO dbo.Location([Line1],[CountryId])
VALUES ('random line','ZZZ')
");
}
But if you have to meet with those requirements
Code must run in one transaction i.e. I cannot commit changes before the ExecuteSqlCommand
you should avoid mixing SQL statements and EF-like code.
In that situation (I assume that you have all FKs defined correctly) you should be able to do sth like that:
using (var context = new EarthContext())
{
var country = new Country(){
Id = "ZZZ",
IsoCodeAlpha2 = "ZZ",
IsoCodeNumberic = 999
};
context.Countries.Add(country);
country.Locations.Add(new Location() { Line1 = "random line" } );
context.SaveChanges();
}

Related

Get the last inserted item using Document Model or Object Persistence Model using .Net core with DynamoDB

I am able to get the last inserted item using low level API as showed in code below using .net core
But is it possible to get the last inserted item using high level API such as Document Model or Object Persistence Model?
Prefer Object Persistence Model if possible. I am not able to find a way to do it, also, I would like DynamoDB to query and return the last item only. I understand that I can get a list of items inserted and get the last item myself in memory, but it is not preferable since it require a lot more read and data transfer.
Thanks
public async Task<DailyStockRecordDao> GetTheLastInsertedItem(string tickerSymbol)
{
QueryRequest request = getTheLastItemRequest(tickerSymbol);
var response = await _dynamoDBClient.QueryAsync(request);
return null;
}
private static QueryRequest getTheLastItemRequest(string tickerSymbol)
{
string partitionName = ":v_PartitionKeyName";
var request = new QueryRequest
{
TableName = Constants.TableName,
KeyConditionExpression = $"{Constants.PartitionKeyName} = {partitionName}",
ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
{ $"{partitionName}", new AttributeValue {
S = tickerSymbol
} }
},
// Optional parameter.
ConsistentRead = false,
Limit = 1,
ExclusiveStartKey = null,
ScanIndexForward = false
};
return request;
}
You can have the below data-structure to achieve this.
pk value
----------------------------------------------
key1 value1
key2 value2
key3 value3
latest {key: key1, value:value1}
While doing write, do 2 writes instead of 1. and while reading just do a get using pk=latest.
Can you add one more column called created_counter, and insert the value starting with numeric 1, then 2, then 3 and so on?
Make the created_counter as sort key.
To reverse the order, set the ScanIndexForward parameter to false.
Use limit 1, to get the last inserted data.

What is the Partiton Key value when it's null?

I've got records that were the result of bad data where the Partition Key is null and I need to clean them up, but I've been unsuccessful so far.
Here's what I've tried:
var scriptResult = await _dbClient.ExecuteStoredProcedureAsync<dynamic>(
GetStoredProcLink("BulkDelete"),
new RequestOptions() { PartitionKey = new PartitionKey(""), EnableScriptLogging = true },
"select * from c where c.documentDbType = "SomeValue"");
I've also tried used Undefined.Value as the parameter to new PartitionKey().
I ripped the stored proc from here and haven't changed anything yet.
Note: This is a partitioned collection if it was not obvious (by /companyId)
I just hit this issue when migrating to new database level throughput provision. This is syntax that got me up and running again when my models did not contain the specified partition Key property:
new RequestOptions() {
PartitionKey = new PartitionKey(Undefined.Value)
}
Ref:
https://www.lytzen.name/2016/12/06/find-docs-with-no-partitionkey-in-azure.html
Null, Undefined, and empty string are all different values in Cosmos DB. You need something like: new RequestOptions { PartitionKey = new PartitionKey(null) }

Which rows were deleted? [duplicate]

I need to run two statements like so:
Select amount from db where ID=5
DELETE from db where ID=5
Currently I prepare and run two different statements. I wonder if there is a way to combine it in one statement.
Basically all I need to do is to get an amount column from the row before it is deleted.
SQLite does not support this extension to standard SQL -- you do have to use both statements, SELECT first, DELETE next. You can wrap them in a transaction, of course, (BEGIN and COMMIT statements before and after will guarantee that), to guarantee atomicity and consistency.
If you just want to select rows and delete them in one pass, you can use the returning clause in the delete statement.
For instance:
delete from myTable returning *
The delete statement has all select functionalities possible such as with and where that permits to select rows with any logic.
Assuming that your calling thread/process has a unique identifier (e.g. thread_id), I think a viable approach would be to add a flag (say, "handlerid") to your table, which is set to null on insert, and then do:
update db set handlerid = <my_thread_id> where handlerid is null;
select * from db where handlerid is not null and handlerid = <my_thread_id>;
delete from db where handlerid is not null and handlerid = <my_thread_id>;
Not sure how it would perform vs a transaction but can't think of any reason it would be materially worse (might even be better), and using this approach the code seems about as straightforward as you can get. unlike a transaction, it won't require you to loop in the case that a transaction fails, in order to be sure that all outstanding elements that were in the table at the time of the most recent SELECT got processed.
It's late but for future visitor. In my case I did like below
I want to delete that ID where amount = 5 so I did this
public void selectAndDelete() {
try {
SQLiteDatabase db = this.getWritableDatabase();
int i=db.delete(table_name, "ID = (select ID from table_name where amount = 5)", null);
if(i>0)
{
// I'm inserting here new record
}
} catch (SQLException e) {
}
}
So, In your case you need to modify where condition like you want
You can do this by separating the two statements with a semicolon, e.g. (using the .NET port of SQLite):
using (SQLiteConnection conn = new SQLiteConnection("Data Source=fie.db3"))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT id FROM fies; DELETE FROM fies WHERE id = 5;";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader[0]);
}
}
}
}

Joins and anonymous types in SQLite

I'm trying to do a few LINQ statements in SQLite but I'm getting a few problems.
First I'm trying to do a join. Here is my code:
var query = from client in db.Table<Client>()
join address in db.Table<AddressDetail>()
on client.AddressID equals address.AddressID
select new
{
ClientID = client.ClientID,
AddressID = address.AddressID,
Name = address.Name,
LastSaveDate = client.LastSaveDate
};
This fails and the error message I receive is : Joins are not supported.
Brilliant!!
So to get round this I split my code into 2 queries, so here is the updated code:
var query = db.Table<Client>();
foreach (var client in query)
{
var subQuery = from address in db.Table<AddressDetail>()
where address.AddressID == client.AddressID
select new
{
ClientID = client.ClientID,
AddressID = address.AddressID,
Name = address.Name,
LastSaveDate = client.LastSaveDate
};
foreach (var fullClient in subQuery)
{
//Do something here
}
}
This all seems to work until I try to loop round the results of the subQuery.
I receive the following error: No parameterless constructor defined for this object.
So do this mean that I can't use joins and anonymous types in SQLite?
Any ideas how I can get round this.
I'm using the SQLite, .Net 4.5 and am create a Windows 8 store app.
Had you try this?
just add ToList() to table you want to join.
var query = from client in db.Table<Client>()
join address in db.Table<AddressDetail>().ToList()
on client.AddressID equals address.AddressID
select new
{
ClientID = client.ClientID,
AddressID = address.AddressID,
Name = address.Name,
LastSaveDate = client.LastSaveDate
};

Update table with LINQ

SOLVED look below code snippet.
I have a problem with updating tables, The code shows no faults but it don't act as expected, it does not put any information in the Log Table.
some explenation, i have a table called User with a FK on LogID and a table called Log with PK on LogID so that should be correct, the Log has a column called TimesLoggedIn and one called LastLogedin. and i want to update them accordingly.
User logid = db.Users.Single(p => p.UserID == loginID);
logid.Log.LastLogedin= DateTime.UtcNow;
if (logid.Log.TimesLoggedIn == null)
{
logid.Log.TimesLoggedIn = 1;
}
else
{
logid.Log.TimesLoggedIn = logid.Log.TimesLoggedIn + 1;
}
db.SubmitChanges();
had an embarrassing fault in my code, i had
Response.Redirect("ControlPanel");
placed before i ran the LINQ not after.
I'm using Entity Framework, so I might be wrong. But maybe the Log isn't loaded at all.
Try this:
var options = New DataLoadOptions();
options.LoadWith<Users>(x => x.Log);
db.LoadOptions = options;
// then your code:
User logid = db.Users.Single(p => p.UserID == loginID);
logid.Log.LastLogedin= DateTime.UtcNow;
....

Resources