I played with the same code that uses the #Query annitation e.g.
#Query(value = "SELECT * FROM c")
List<User> getAllUsers();
However, how do I do the equivalent of SQL Update e.g.?
#Query(value = "UPDATE c set c.firstName = #documentFirstName")
void updateUsersName(#Param("documentFirstName") String documentFirstName);
This example above doesn't work, is there some other syntax?
The Cosmos DB SQL API only supports the Select statement. Partially updating a document isn't supported yet.
If you are using the SDK, To update a document you have to use the Upsert-Method:
DocumentClient.UpsertDocumentAsync Method
UPDATE:
Partial update feature is supported since November 2021. The feature is GAed.
Related
I'm having issues with a Linq query that can't be translated, but before I go into detail on the code, I have a general question.
My query works if I test my Web Api locally with IIS, but when I publish it to Azure, it gives me an error, saying that it can't be translated.
So my question is, what could be the reason for this? How is it possible, that it produces different results after publish? It's really annoying to make something work only to find out later that it doesn't work when published. This way I will have to publish all of the time to make sure that it actually works.
For the actual problem, my query looks like this:
var innerJoinQuery =
from user in _context.Users
join historyentry in _context.ResourceHistory on user.UserId equals historyentry.UserId
join resource in _context.UserResource on historyentry.UserId equals resource.UserId
join userProfile in _context.UserProfiles on resource.UserId equals userProfile.UserId
where historyentry.ShortName.Equals(shortName)
&& historyentry.CreatedUtc > startUtc
&& historyentry.CreatedUtc < endUtc
select new BoardEntry()
{
UserId = user.UserId,
ResourceShortName = resource.ShortName,
ResourceDisplayName = resource.DisplayName,
UserDisplayName = userProfile.DisplayName,
Amount = historyentry.Amount
};
This is the error I get:
The LINQ expression 'ROW_NUMBER() OVER(PARTITION BY u2.UserId ORDER BY
u2.UserId ASC, r0.HistoryEntryId ASC, u3.ResourceId ASC, u4.ProfileId
ASC)' could not be translated. Either rewrite the query in a form that
can be translated, or switch to client evaluation explicitly by
inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or
'ToListAsync'.
Setup:
EF Core 5.0.17
MariaDB 10.3
Pomelo.EntityFrameworkCore.MySql 5.0.4
Staring from EF Core 5.0 for subqueries which has row count limitation (Take(1), FirstOrDefault, etc.) instead of CROSSS/OUTER APLLY, LINQ Translator generates join to query with Window function ROW_NUMBER. Not all versions of MariaDB supports Window functions and probably Pomelo.EntityFrameworkCore.MySql provider has bug in server version autodetection for MariaDB, so try to specify version explicitly:
builder.UseMySql(connectionString, serverVersion);
Is there any DATEADD-like functionality in Cosmos DB SQL API?
Fairly new to the SQL API for Cosmos DB and am looking for a functionality that would be close to DATEADD in SQL. Is there any? I've reviewed the system functions on the MS website but couldn't find any.
SELECT count(1)
FROM c
where c.composed_at < dateadd("day",-30,c.composed_at)
User Defined Functions maybe the route to take.
https://learn.microsoft.com/en-us/azure/cosmos-db/sql-query-udfs
You could define an udf in your cosmos db collection.
function getLastMonth(){
var date = new Date();
var a = date.setDays(-30);
return a;
}
Modify your sql to :
SELECT * FROM c where c.composed_at < udf.getLastMonth()
Note: udf.getLastMonth() returns Unix time stamp , you need to match the format.
Hope it helps you.
In my test project I register a connection using ":memory" connection string and SqliteDialect.Provider as provider. When trying to run tests that execute arbitrary sql (I have a complex join statement so I cannot use a typed query) I get an error that the table do not exist. In my query I print "SELECT * FROM xxx.Table1" but when looking at the code generated from a typed query I can see that it is "SELECT * FROM xxx_Table1". I need to use schemas for the production code, so is there a way to force ORMLite for Sqlite to generate schemas and not just name prefixes when using the attribute [Schema("xxx")] on my domain models?
SQLite doesn't have schemas so they're simulated by prefixing the schema name before the table name. However this should be a transparent implementation detail for SQLite :memory: DBs as the same table name will be used when creating or querying the table.
If you're creating Custom SQL you should use the tableName returned from:
var modelDef = typeof(Table1).GetModelMetadata();
var tableName = db.GetDialectProvider().GetTableName(modelDef);
var sql = $"SELECT * FROM {tableName}";
Let's say i have a table named User.
When I use the Entity Framework to get the records i do like this:
var db = new Context();
var users = db.Users;
It return all the users in my table. OK. If i do this:
var fooUsers = db.Users.Where(u => u.Name == 'foo');
It will give me all the users with name 'foo'. OK. My question is:
The entity framework make a query like:
select * from user where name = 'foo'
Or it load all the users and filter them on the server with lambda expression?
The Sql submitted to your database will contain your where clause. You can use SQL Server Profiler to watch as queries are submitted to your DB.
Entity Framework will translate such a query into a "Store Expression." That is, it will generate a database query -- assuming your data storage is a database -- that will be somewhat similar to the query you included in your question. It very well may name the columns, however, and there are likely to be some other differences.
From here http://msdn.microsoft.com/en-us/library/cc853327.aspx
When you create an ObjectQuery or LINQ query, the query may not be executed immediately. Query execution is deferred until the results are needed, such as during a foreach (C#) or For Each (Visual Basic) enumeration or when it is assigned to fill a List collection. Query execution begins immediately when you call the Execute method on an ObjectQuery or when you call a LINQ method that returns a singleton query, such as First or Any. For more information, see Object Queries and Query Execution (LINQ to Entities).
So when your query has a WHERE clause it will just load the results filtered by the database with the where.
I am using Xerial latest jdbc driver for sqlite (version 3.7.2) It does not seem to have support for Statement RETURN_GENERATED_KEYS. I keep getting "not implemented by SQLite JDBC driver" in the SQLException.
I really do not want to make another select call (e.g select id from tasks order by 1 desc limit 1 ) in order to get the latest Id created by an auto-increment field. I need to use that id to populate a field in another table.
Are there any better ways of achieving this using sqlite-jdbc driver ?
If upgrading/replacing the JDBC driver is not an option (the SQLiteJDBC seem to support it), then you really need to fire a SELECT last_insert_rowid() query to obtain the generated key. To avoid race conditions with concurrent inserts, fire it in a transaction.
connection = database.getConnection();
connection.setAutoCommit(false); // Starts transaction.
preparedStatement = connection.prepareStatement(INSERT_SQL);
preparedStatement.setSomething(something);
// ...
preparedStatement.executeUpdate();
statement = connection.createStatement();
generatedKeys = statement.executeQuery("SELECT last_insert_rowid()");
if (generatedKeys.next()) {
generatedKey = generatedKeys.getLong(1);
}
connection.commit(); // Commits transaction.
I'm also using sqlite-jdbc-3.7.2.jar and found that using RETURN_GENERATED_KEYS does fail, however merely doing a statement.execute(sql) followed by resultset = statement.getGeneratedKeys() and meta = resultset.getMetaData() shows that a column name last_insert_rowid() is available in the resultset. So resultset.getInt("last_insert_rowid()") does indeed return the newly inserted rowid without an additional select.