Is there a way to update a database field based on a list? - jpa

Using JPA, I have a list of entries from my database :
User(id, firstname, lastname, email)
That I get by doing:
List<User> users = User.find("lastname = ?", "smith");
And I'd like to update all in one request, by doing something like this :
"UPDATE USER SET email = null IN :list"
and then set the parameter "list" to users
Is it possible? if so, how?
Thanks for your help :)

Well, you could embed the query that you used to obtain list in the where clause of the update.
UPDATE User a SET a.email = null
WHERE user IN (SELECT b FROM User b WHERE lastName = :?)
By doing this you'd be doing the query to search the list and the update in single update query.
How do you like that? Do you think this could work?
-EDIT-
Since you want to use the original list of items instead of a list just retrieved from the database, you can still ensure you build the original list like this
UPDATE User a SET a.email = null
WHERE user IN (SELECT b FROM User b WHERE lastName IN(:originalList))
Then when you invoke it, you can do something like this:
Collection<String> originalList = Arrays.asList("Kenobi", "Skywalker", "Windu");
query.setParameter("originalList", originalList);
By this, you can still ensure the query will only contain items in your original list and not any possible new item from the database, provided that that last name is a candidate key in the database, otherwise I would recommend that you use the ID for the subquery instend of the last name.

if you have jpa+hibernate you can use entityManager.createQuery() for creating hql query
like that:
String hql = "UPDATE Supplier SET name = :newName WHERE name IN :name";
entityManager.createQuery(hql);

Related

Copy Product Price into a Custom Field Object using APEX Trigger in Salesforce

Trying to just copy the Cost_Price__c field of a product into a custom object when it is updated (if possible inserted too) using an APEX trigger.
I'm so close but the error I am getting at the moment is: Illegal assignment from PricebookEntry to String
trigger updateAccount on Account (after update) {
for (Account oAccount : trigger.new) {
//create variable to store product ID
string productId = oAccount.Product__c;
//SQL statement to lookup price of product using productID
PricebookEntry sqlResult = [SELECT Cost_Price__c
FROM PricebookEntry
WHERE Product2Id =: productId];
//save the returned SQL result inside the field of Industry - Illegal assignment from PricebookEntry to String
oAccount.Industry = sqlResult;
}
}
Am I right in thinking it's because its returning a collective group of results from the SOQL call? I've tried using the sqlResult[0] which still doesn't seem to work.
The Illegal Assignmnet because you are assigning a whole Object i.e PriceBook Entry to a string type of field i.e Industry on Account.
Please use the following code for assignment.
oAccount.Industry = sqlResult[0].Cost_Price__c;
Please mark the answer if this works for you.
Thanks,
Tushar

Why can't I create model based results from lync but I can do anything through SqlQuery?

Any idea why this doesn't work
return View((from u in db.Users
select new Models.Users()
{
Id = u.Id,
Username = u.Username,
Password = "-"
}).ToList());
And this works like a charm? :]
return View(db.Users.SqlQuery("SELECT Id, Username, '-' AS Password FROM Users"));
Since you didn't really give a ton of information I'm gonna take a shot in the dark. EF doesn't allow you to select to a class that represents a database entity. I'm assuming the Models.Users class is the same class being used in your db.Users? You should just be able to create like a UserDto with the same fields and I think that will work. If it doesn't give more info and I'll try to help more.

Many-to-Many Inserts with Entity Framework

Say I have two entities with about 20 properties per entity and a Many-to-Many relationship like so:
User (Id int,Name string, .......)
Issue (Id int,Name string, .......)
IssueAssignment (UserId,RoleId)
I want to create a new Issue and assign it to a number of existing Users. If I have code like so:
foreach(var userId in existingUserIds)
{
int id = userId
var user = _db.Users.First(r => r.Id == id);
issue.AssignedUsers.add(user);
}
_db.Users.AddObject(user);
_db.SaveChanges();
I noticed it seems terrribly inefficient when I run it against my SQL Database. If I look at
the SQL Profiler it's doing the following:
SELECT TOP(1) * FROM User WHERE UserId = userId
SELECT * FROM IssueAssignment ON User.Id = userId
INSERT INTO User ....
INSERT INTO IssueAssignment
My questions are:
(a) why do (1) and (2) have to happen at all?
(b) Both (1) and (2) bring back all fields do I need to do a object projection to limit the
fields, seems like unnecessary work too.
Thanks for the help
I have some possible clues for you:
This is how EF behaves. _db.Users is actaully a query and calling First on the query means executing the query in database.
I guess you are using EFv4 with T4 template and lazy loading is turned on. T4 templates create 'clever' objects which are able to fixup their navigation properties so once you add a User to an Issue it internally triggers fixup and tries to add the Issue to the User as well. This in turns triggers lazy loading of all issues related to the user.
So the trick is using dummy objects instead of real user. You know the id and you only want to create realtion between new issue and existing user. Try this (works with EFv4+ and POCOs):
foreach(var userId in existingUserIds)
{
var user = new User { Id = userId };
var _db.Users.Attach(user); // User with this Id mustn't be already loaded
issue.AssignedUsers.Add(user);
}
context.Issues.AddObject(issue);
context.SaveChanges();

Entity Framework, How to include related entities in this example

I have a table AccountSecurity which is a many-to-many table that relates Account entities and Securities. When I write the query below it returns all Securities that satisfy the where clause. However each Security instance in the list no longer has the reference to the AccountSecurity it came from. So when I do list[0].AccountSecurity it is empty. Is there anyway to include that information? I know I can rewrite the query to return AccountSecurities instead and use .Include("Security") on that, but I wonder if it can be done another way.
var list = (from acctSec in base.context.AccountSecurities
where acctSec.AccountId == accountId
select acctSec.Security).ToList();
UPDATE
Of course if I do two queries the graph gets populated properly, there has to be a way to do this in one shot.
var securities = (from acctSec in base.context.AccountSecurities
where acctSec.AccountId == accountId
select acctSec.Security).ToList();
//this query populates the AccountSecurities references within Security instances returned by query above
var xref = (from acctSec in base.context.AccountSecurities
where acctSec.AccountId == accountId
select acctSec).ToList();
var list = (from sec in base.context.Securities
.Include("AccountSecurity")
where sec.AccountSecurities.Any(as => as.AccountId == accountId)
select sec).ToList();
Try this:
var list = (from acctSec in base.context.AccountSecurities.Include("Security")
where acctSec.AccountId == accountId
select acctSec).ToList();
Then simply use the Security property as needed, and since it's read at the same time AccountSecurities is (single SQL with join), it will be very efficient.

Using ObjectQuery Include and using a nested where clause

Using entity framework, I'm trying to get back a customer with order details but I want to filter out those Orders that are active.
Customer is our EntityObject which has a collection of Order EntityObjects. CustomerDetails is our ObjectContext.
The code below will attach all orders but I want to filter and only attach those that are active. (Order.active == true). How can I do this?
I know Include builds up a nested query statement (I can observe by using .ToTraceString().) I was hoping to attach a Where clause to this nested select statement or the Include.
Customer cust;
CustomerDetails custTable = new CustomerDetails();
cust = custTable.Customer
.Where("it.cust_id = " + id)
.Include("Order") // But we only want Order.active == true!!!
.ToList().First();
Untested, but might work?
var temp = custTable.Customer.Where("it.cust_id = " + id).Include("Order");
cust = (from t in temp
where t.Order.active == true
select t).ToList().First();