Multiple DAO update in single query through Exposed? - kotlin-exposed

normally I can create a SQL query like this to update two separate tables:
UPDATE Books, Orders
SET Orders.Quantity = Orders.Quantity + 2,
Books.InStock = Books.InStock - 2
WHERE
Books.id = Orders.BookID
AND Orders.id = 1002;
DAO would be like:
internal object Books : LongIdTable() {
val InStock: Column<Long> = long("in_stock")
}
internal object Books : LongIdTable() {
val Quantity: Column<Long> = long("quantity")
val BookID: Column<Long> = long("book_id").references(Books.id)
}
What's the recommended way to perform similar SQL query using Exposed?
2) Separate question, can we write two update queries in a single transaction block? Something like this:
transaction {
TableA.update({ TableA.id eq id }) { row ->
row[TableA.status] = appStatus
}
TableB.update({ TableB.appID eq id }) { row ->
row[TableB.status] = userStatus
}
}
Thanks for any pointers.

Yes, you can write more than one statement per transaction block, and I think it is a reasonable way to implement your update

Related

How to increase the value of a text by my database

I want to change the value of a variable called "value" which represent the shown value in the screen according to my database, here is my code
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val mViewModel = ViewModelProvider(this).get(ExpenseCalculatorViewModel::class.java)
binding.categoryName.text = args.category
val viewModel = ViewModelProvider(this).get(CategoriesViewModel::class.java)
when (binding.categoryName.text) {
getString(R.string.restaurant) -> {
viewModel.readRestaurantData.observe(viewLifecycleOwner, {
var value = 0
for (i in it.indices) {
value += it[i].restaurant
}
binding.totalNumber.text = value.toString()
})
}
please I need a useful answer and thanks for your patience
You need to perform an update query. Using ROOM for your SQLITE, you create the update query on your DAO class, you can call RestaurantDao. Allocate all your queries there such as update, delete, insert, etc.
Example: (modify the names of the table and variables according to your table structure.
#Query("UPDATE my_restaurant_table SET value=:value " +
"WHERE id=:id"
) public abstract void updateRestaurant(
long id,
String value
);

Get only dataValues from sequelize raw query instead of Model instance

I'm using sequelize and using raw query to get the datas from table. But I'm getting all of the model instances while I only need the dataValues.
My setup looks like this:
const sequelize = new Sequelize({
database: process.env.PGDATABASE,
username: process.env.PGUSER,
password: process.env.PGPASS,
host: process.env.PGHOST,
port: process.env.PGPORT,
dialect: "postgres"
});
getPostGres: () => {
return sequelize;
}
and the way I'm querying the database looks like this:
let messageRatingsArr = await getPostGres().query(
`SELECT mr.support_email, mr.support_name,
(select count(mrn."chatId") as total FROM message_ratings as mrn WHERE mrn."ratingType"='NEGATIVE' and mr.support_email = mrn.support_email) as negative,
(select count(mrp."chatId") as total FROM message_ratings as mrp WHERE mrp."ratingType"='POSITIVE' and mr.support_email = mrp.support_email) as positive,
(select count(mrm."chatId") as total FROM message_ratings as mrm WHERE mrm."ratingType"='MIXED' and mr.support_email = mrm.support_email) as mixed,
(select count(mru."chatId") as total FROM message_ratings as mru WHERE mru."ratingType"='NEUTRAL' and mr.support_email = mru.support_email) as neutral
FROM message_ratings mr
WHERE mr."createdAt" >= '${properFromDate}' AND mr."createdAt" <= '${properToDate}'
group by mr.support_email, mr.support_name
limit ${args.count} offset ${args.offset} `,
{
model: MessageRatingPG,
mapToModel: true
}
);
let messageRatings = messageRatingsArr.map(item=>{
return item.dataValues;
})
let result = connectionFromArray(messageRatings, args);
result.totalCount = messageRatings.length;
return result;
As you can see, since I'm mapping the data from the query which has all kinds of stuff like dataValues, _options, isNewRecord etc., looping through the array if I have a large data set isn't efficient, so what can I do to only get the dataValues?
From https://sequelize.org/master/manual/raw-queries.html:
In cases where you don't need to access the metadata you can pass in a query type to tell sequelize how to format the results. For example, for a simple select query you could do:
sequelize.query("SELECT * FROM `users`", { type: sequelize.QueryTypes.SELECT})
.then(users => {
// We don't need spread here, since only the results will be returned for select queries
})
Now, looking at your code, and comparing with the next paragraph in the docs:
A second option is the model. If you pass a model the returned data will be instances of that model.
// Callee is the model definition. This allows you to easily map a query to a predefined model
sequelize
.query('SELECT * FROM projects', {
model: Projects,
mapToModel: true // pass true here if you have any mapped fields
})
.then(projects => {
// Each record will now be an instance of Project
})
I'd suggest removing from your original code, the following:
{
model: MessageRatingPG,
mapToModel: true
}
and replacing it with { type: sequelize.QueryTypes.SELECT }
You have to add to your query the attribute raw. From the docs
Sometimes you might be expecting a massive dataset that you just want
to display, without manipulation. For each row you select, Sequelize
creates an instance with functions for update, delete, get
associations etc. If you have thousands of rows, this might take some
time. If you only need the raw data and don't want to update anything,
you can do like this to get the raw data.
Project.findAll({ where: { ... }, raw: true })

Dapper SqlBuilder OrWhere using AND instead of OR

I was trying to use the Where and OrWhere methods of SqlBuilder for Dapper, but it is not acting like how I would expect.
The edited portion of this question is basically what I ran into. Since it didn't receive a response, I'll ask it here.
var builder = new SqlBuilder();
var sql = builder.AddTemplate("select * from table /**where**/ ");
builder.Where("a = #a", new { a = 1 })
.OrWhere("b = #b", new { b = 2 });
I expected select * from table WHERE a = #a OR b = #b
but I got select * from table WHERE a = #a AND b = #b
Is there any way to add an OR to the where clause using the SqlBuilder?
I think it's just a matter of changing the following in the SqlBuilder class to say OR instead of AND, but I wanted to confirm.
public SqlBuilder OrWhere(string sql, dynamic parameters = null)
{
AddClause("where", sql, parameters, " AND ", prefix: "WHERE ", postfix: "\n", IsInclusive: true);
return this;
}
Nevermind. I looked through the SqlBuilder code and found that if there is a mixture of Where and OrWhere, it will do the following:
Join all the AND clauses
Join all the OR clauses separately
Attach the OR clauses at the end of the AND clauses with an AND
If you don't have more than 1 OrWhere, then you won't see any OR.
I'll modify my query logic to take this into account
You have to change your query into:
var builder = new SqlBuilder();
var sql = builder.AddTemplate("select * from table /**where**/ ");
builder.OrWhere("a = #a", new { a = 1 })
.OrWhere("b = #b", new { b = 2 });
In case you want to try another alternative, DapperQueryBuilder may be easier to understand:
var query = cn.QueryBuilder($#"
SELECT *
FROM table
/**where**/
");
// by default multiple filters are combined with AND
query.FiltersType = Filters.FiltersType.OR;
int a = 1;
int b = 2;
query.Where($"a = {a}");
query.Where($"b = {b}");
var results = query.Query<YourPOCO>();
The output is fully parametrized SQL (WHERE a = #p0 OR b = #p1).
You don't have to manually manage the dictionary of parameters.
Disclaimer: I'm one of the authors of this library

Audit of what records a given user can see in SalesForce.com

I am trying to determine a way to audit which records a given user can see by;
Object Type
Record Type
Count of records
Ideally would also be able to see which fields for each object/record type the user can see.
We will need to repeat this often and for different users and in different orgs, so would like to avoid manually determining this.
My first thought was to create an app using the partner WSDL, but would like to ask if there are any easier approaches or perhaps existing solutions.
Thanks all
I think that you can follow the documentation to solve it, using a query similar to this one:
SELECT RecordId
FROM UserRecordAccess
WHERE UserId = [single ID]
AND RecordId = [single ID] //or Record IN [list of IDs]
AND HasReadAccess = true
The following query returns the records for which a queried user has
read access to.
In addition, you should add limit 1 and get from record metadata the object type,record type, and so on.
I ended up using the below (C# using the Partner WSDL) to get an idea of what kinds of objects the user had visibility into.
Just a quick'n'dirty utility for my own use (read - not prod code);
var service = new SforceService();
var result = service.login("UserName", "Password");
service.Url = result.serverUrl;
service.SessionHeaderValue = new SessionHeader { sessionId = result.sessionId };
var queryResult = service.describeGlobal();
int total = queryResult.sobjects.Count();
int batcheSize = 100;
var batches = Math.Ceiling(total / (double)batcheSize);
using (var output = new StreamWriter(#"C:\test\sfdcAccess.txt", false))
{
for (int batch = 0; batch < batches; batch++)
{
var toQuery =
queryResult.sobjects.Skip(batch * batcheSize).Take(batcheSize).Select(x => x.name).ToArray();
var batchResult = service.describeSObjects(toQuery);
foreach (var x in batchResult)
{
if (!x.queryable)
{
Console.WriteLine("{0} is not queryable", x.name);
continue;
}
var test = service.query(string.Format("SELECT Id FROM {0} limit 100", x.name));
if(test == null || test.records == null)
{
Console.WriteLine("{0}:null records", x.name);
continue;
}
foreach (var record in test.records)
{
output.WriteLine("{0}\t{1}",x.name, record.Id);
}
Console.WriteLine("{0}:\t{1} records(0)", x.name, test.size);
}
}
output.Flush();
}

LINQ to SQL for self-referencing tables?

I have a self referencing Categories table. Each Category has a CategoryID, ParentCategoryID, CategoryName, etc. And each category can have any number of sub categories, and each of those sub categories can have any number of sub categories, and so and and so forth. So basically the tree can be X levels deep.
Then Products are associated to leaf (sub) Categories. Is there a way to get all the Products for any given Category (which would be all the products associated to all its leaf descendants) using LINQ to SQL?
This feels like a recursive problem. Is it better to used a Stored Procedure instead?
I don't think linq-to-sql has a good answer to this problem. Since you are using sql server 2005 you can use CTEs to do hierarchical queries. Either a stored procedure or an inline query (using DataContext.ExecuteQuery) will do the trick.
Well here is a terrible rushed implementation using LINQ.
Don't use this :-)
public IQueryable GetCategories(Category parent)
{
var cats = (parent.Categories);
foreach (Category c in cats )
{
cats = cats .Concat(GetCategories(c));
}
return a;
}
The performant approach is to create an insert/modify/delete trigger which maintains an entirely different table which contains node-ancestor pairs for all ancestors of all nodes. This way, the lookup is O(N).
To use it for getting all products belonging to a node and all of its descendants, you can just select all category nodes which have your target node as an ancestor. After this, you simply select any products belonging to any of these categories.
The way I handle this is by using some extension methods (filters). I've written up some sample code from a project I have implemented this on. Look specifically at the lines where I'm populating a ParentPartner object and a SubPartners List.
public IQueryable<Partner> GetPartners()
{
return from p in db.Partners
select new Partner
{
PartnerId = p.PartnerId,
CompanyName = p.CompanyName,
Address1 = p.Address1,
Address2 = p.Address2,
Website = p.Website,
City = p.City,
State = p.State,
County = p.County,
Country = p.Country,
Zip = p.Zip,
ParentPartner = GetPartners().WithPartnerId(p.ParentPartnerId).ToList().SingleOrDefault(),
SubPartners = GetPartners().WithParentPartnerId(p.PartnerId).ToList()
};
}
public static IQueryable<Partner> WithPartnerId(this IQueryable<Partner> qry, int? partnerId)
{
return from t in qry
where t.PartnerId == partnerId
select t;
}
public static IQueryable<Partner> WithParentPartnerId(this IQueryable<Partner> qry, int? parentPartnerId)
{
return from p in qry
where p.ParentPartner.PartnerId == parentPartnerId
select p;
}

Resources