Ecto.Repo to check if id exists in the database, Phoenix framework - phoenix-framework

How do I check if an id exists in the database?
def get_user!(id), do: Repo.get!(User, id)
get_user!(id) can be used to get the user, is there a way to check if id exists?
I want something like below which would return true.
MyApp.Accounts.get_user!(user_id) == %MyApp.Accounts.User{id: user_id}

Ecto v3 supports this with Ecto.Repo.exists?/2
import Ecto.Query, only: [from: 2]
Repo.exists?(from u in User, where: u.id == ^user_id)

Repo.get! throws an error if no record is found.
You might want to use Repo.get instead like
Repo.get(User, user_id) != nil
You can also define a function to check if a give user id exists
def user_exist_by_id(user_id)do
#select just id to reduce payload
query = (from u in User, where: u.id == ^user_id, select: %{id: u.id})
found = Repo.one(query)
#if not result, found will be nil
found != nil
end

Related

How to create boolean field that check the current user in odoo V11?

I'm working on Employee directory module in Odoo 11 and I want to create a compute field that check for each employee if it's related user is equivalent to the current user (logged user).
I create the compute function but it allways return false.
Python code :
user_id = fields.Many2one('res.users', 'User', related='resource_id.user_id')
current_user = fields.Boolean('is current user ?', compute='_get_current_user')
#api.depends('user_id')
def _get_current_user(self):
for e in self:
e.current_user = (self.env.user.id == e.user_id)
Any help please ?
Try out this code.
user_id = fields.Many2one('res.users', 'User', related='resource_id.user_id')
current_user = fields.Boolean('is current user ?', compute='_get_current_user')
#api.depends('user_id')
def _get_current_user(self):
for e in self:
e.current_user = (True if e.env.user.id == e.user_id.id else False)

what does a linq query return when no results are found

i'm using a query to see if a user already exists in the database. if it finds a user, it adds it to the list (not database), and presents a message. if the user does NOT already exist, the program moves on to add the user.
the problem exists when adding the query result to a list, when the result found nothing. if the query found nothing (user does not yet exist) the returned value isn't null or 0, so i'm not sure how to check for this.
my code works fine, but my problem is trying to find a more elegant approach. i try to add the query results to a list. if it his the "catch", it means the user does not exist and it shall be added. right now my code is:
var userIsNew =
from f in controlEntities.Users
where (f.UserId == userIdTextBox.Text)
select f;
List<Users> temp = new List<Users>();
try
{
temp = userIsNew.ToList<Users>();
}
catch
{
//do nothing
}
if (temp.Count > 0)
{
MessageBox.Show("This UserId already exists in the Database. \nPlease try another UserId.");
}
thank you for your help!
var userIsNew = (from f in controlEntities.Users
where (f.UserId == userIdTextBox.Text)
select f).FirstOrDefault();
if (userIsNew != null)
{
MessageBox.Show("This UserId already exists in the Database. \nPlease try another UserId.");
}
Another way would be:
bool userIsNew = controlEntities.Users.
Count(f => f.UserId == userIdTextBox.Text) == 0;
if (!userIsNew)
{
MessageBox.Show("This UserId already exists in the Database. \nPlease try another UserId.");
}
It's efficient because the data server returns only a number instead of a resulset.

"first" helper method

I've been looking at a project for a login module, but I'm not sure exactly what this helper method is doing:
def self.authenticate(login, pass)
u = User.first(:login => login)
return nil if u.nil?
return u if User.encrypt(pass, u.salt) == u.hashed_password
nil
end
Why not instead of:
u = User.first(:login => login)
...you do something like:
u = self.login
Thanks!
The first helper method locates the first record in your database that matches the specified criteria. It's semantically equivalent to the following SQL statement:
SELECT * FROM Users WHERE login = 'foo' LIMIT 1
The code after u = User.first(:login => login) does the following:
1. Checks to see if there is a user returned with the specified login
2. Returns the User object if the passwords match.
u = User.first(:login => login)
means "go to the database, and find me the first User object whose login equals the userid passed in as the "login" parameter. Assign this to u.
Because you're looking for the corresponding user object, not just the login name.

How to compare case sensitive string in EF?

the Membership Provider ValidateUser using EF is quite simple
public override bool ValidateUser(string username, string password)
{
// Validate User Credentials
var r = db.ST_Users.FirstOrDefault(
x => x.Username.Equals(username) &&
x.Password.Equals(password));
return r != null ? true : false;
}
But this returns true (finds and retrieves the hole object) no matter if I use balexandre or BAleXanDre.
How can I enable EF to compare in case-sensitive mode?
I know how to compare in case insensitive (using the StringComparison.CurrentCultureIgnoreCase overload, but I just want the opposite)
You should not query on the password. You should retrieve the User object and do a password compare locally, because SQL server will do a case insensitive compare for you by default (unless you change your database settings, which is not something you should take lightly).
var r = db.ST_Users.SingleOrDefault(x => x.Username == username);
return r != null && r.Password == password;
Besides, you seem to be storing plain passwords in your database. Depending on the type of application, this might not be a good idea. Try hashing them with a salt. Lots of good information to find about that here on Stackoverflow. For instance, take a look at this question and this website.
I was facing the same issue. I tried:
1. from p in entity.SecurityUsers where p.userName.Equals(userName) && p.password.Equals(password) select p
2. from p in entity.SecurityUsers where p.userName == userName && p.password == password select p
But both of these didn't work. Then I selected USER only..,
var user = (from p in entity.SecurityUsers where p.userName == userName select p).first();
And then compare its password:
return p != null && p.Password == password;

Help required to optimize LINQ query

I am looking to optimize my LINQ query because although it works right, the SQL it generates is convoluted and inefficient...
Basically, I am looking to select customers (as CustomerDisplay objects) who ordered the required product (reqdProdId), and are registered with a credit card number (stored as a row in RegisteredCustomer table with a foreign key CustId)
var q = from cust in db.Customers
join regCust in db.RegisteredCustomers on cust.ID equals regCust.CustId
where cust.CustomerProducts.Any(co => co.ProductID == reqdProdId)
where regCust.CreditCardNumber != null && regCust.Authorized == true
select new CustomerDisplay
{
Id = cust.Id,
Name = cust.Person.DisplayName,
RegNumber = cust.RegNumber
};
As an overview, a Customer has a corresponding Person which has the Name; PersonID is a foreign key in Customer table.
If I look at the SQL generated, I see all columns being selected from the Person table. Fyi, DisplayName is an extension method which uses Customer.FirstName and LastName. Any ideas how I can limit the columns from Person?
Secondly, I want to get rid of the Any clause (and use a sub-query) to select all other CustomerIds who have the required ProductID, because it (understandably) generates an Exists clause.
As you may know, LINQ has a known issue with junction tables, so I cannot just do a cust.CustomerProducts.Products.
How can I select all Customers in the junction table with the required ProductID?
Any help/advice is appreciated.
The first step is to start your query from CustomerProducts (as Alex Said):
IQueryable<CustomerDisplay> myCustDisplay =
from custProd in db.CustomerProducts
join regCust in db.RegisteredCustomers
on custProd.Customer.ID equals regCust.CustId
where
custProd.ProductID == reqProdId
&& regCust.CreditCardNumber != null
&& regCust.Authorized == true
select new CustomerDisplay
{
Id = cust.Id,
Name = cust.Person.Name,
RegNumber = cust.RegNumber
};
This will simplify your syntax and hopefully result in a better execution plan.
Next, you should consider creating a foreign key relationship between Customers and RegisteredCustomers. This would result in a query that looked like this:
IQueryable<CustomerDisplay> myCustDisplay =
from custProd in db.CustomerProducts
where
custProd.ProductID == reqProdId
&& custProd.Customer.RegisteredCustomer.CreditCardNumber != null
&& custProd.Customer.RegisteredCustomer.Authorized == true
select new CustomerDisplay
{
Id = cust.Id,
Name = cust.Person.Name,
RegNumber = cust.RegNumber
};
Finally, for optimum speed, have LINQ compile your query at compile time, rather than run time by using a compiled query:
Func<MyDataContext, SearchParameters, IQueryable<CustomerDisplay>>
GetCustWithProd =
System.Data.Linq.CompiledQuery.Compile(
(MyDataContext db, SearchParameters myParams) =>
from custProd in db.CustomerProducts
where
custProd.ProductID == myParams.reqProdId
&& custProd.Customer.RegisteredCustomer.CreditCardNumber != null
&& custProd.Customer.RegisteredCustomer.Authorized == true
select new CustomerDisplay
{
Id = cust.Id,
Name = cust.Person.Name,
RegNumber = cust.RegNumber
};
);
You can call the compiled query like this:
IQueryable<CustomerDisplay> myCustDisplay = GetCustWithProd(db, myParams);
I'd suggest starting your query from the product in question, e.g. something like:
from cp in db.CustomerProducts
join .....
where cp.ProductID == reqdProdID
As you have found, using a property defined as an extension function or in a partial class will require that the entire object is hydrated first and then the select projection is done on the client side because the server has no knowledge of these additional properties. Be glad that your code ran at all. If you were to use the non-mapped value elsewhere in your query (other than in the projection), you would likely see a run-time exception. You can see this if you try to use the Customer.Person.DisplayName property in a Where clause. As you have found, the fix is to do the string concatenation in the projection clause directly.
Lame Duck, I think there is a bug in your code as the cust variable used in your select clause isn't declared elsewhere as a source local variable (in the from clauses).

Resources