How do I update a SQL row given an ID with LINQ to SQL? - linq-to-sql

Given this schema:
Fruits
- FruitID INT PK
- FruitName NVARCHAR(30)
- FruitStatusID INT NULL FK: Statuses
Statuses
- StatusID INT PK
- StatusName NVARCHAR(30)
If I have a FruitID in hand (just an int, not a Fruit object), how do I update the FruitName and null out FruitStatusID without loading the Fruit object from the database first?
Note: this solution gets me pretty far, but I can't figure out how to null out a FK column.
Answers in C# or VB, thanks!

This works but seems unnecessarily complicated:
''//initialize the values I'm going to null out to something
Dim Tag As Data_Tag = New Data_Tag() With {
.Data_Tag_ID = DataTagID,
.Last_Error_DateTime = New DateTime(),
.Last_Error_Message = "",
.Last_Error_Severity_Type_ID = -1 }
''//start change tracking
DB.Data_Tags.Attach(Tag)
''//record changes to these properties (must be initialized above)
Tag.Last_Error_DateTime = Nothing
Tag.Last_Error_Message = Nothing
Tag.Last_Error_Severity_Type_ID = Nothing
DB.SubmitChanges()
Surely there's a better way!
(note: the weird comment syntax is solely for the code highliger--it doesn't like VB-style comments)

Related

SQLAlchmemy — get related objects with reflected tables

I am quite new to sqlalchemy, I guess I am missing just a little piece here.
There is this Database (sql):
create table CEO (
id int not null auto_increment,
name char(255) not null,
primary key(id),
unique(name)
);
create table Company (
id int not null auto_increment,
name char (255) not null,
ceo int not null,
primary key(id),
foreign key(ceo) references CEO(id)
);
That code:
from sqlalchemy import create_engine, Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import registry, relationship, Session
engine = create_engine(
"mysql+pymysql:xxxxxxxx",
echo=True,
future=True
)
mapper_registry = registry()
Base = mapper_registry.generate_base()
#####################
## MAPPING CLASSES ##
#####################
class CEO(Base):
__table__ = Table('CEO', mapper_registry.metadata, autoload_with=engine)
companies = relationship('Company', lazy="joined")
class Company(Base):
__table__ = Table('Company', mapper_registry.metadata, autoload_with=engine)
##########################
## FINALLY THE QUESTION ##
##########################
with Session(engine, future=True) as session:
for row in session.query(CEO).all():
for company in row.companies:
## Just the id of the Ceo is yielded here
print(company.ceo)
So CEO.companies works as expected, but Company.ceo does not, even though the FOREIGN KEY is defined.
What is a proper setup for the Company Mapper class, such that Company.ceo yields the related object?
I could figure out, that the automatic setup did not work, because the column Company.ceo exists in the Database and represents the ID of a given row. To make everything work, I needed to rename Company.ceo to Company.ceo_id and add the relation manually like so:
CompanyTable = Table('Company', Base.metadata, autoload_with=engine)
class Company(Base):
__table__ = CompanyTable
ceo_id = CompanyTable.c.ceo
ceo = relationship('CEO')
I would like to know if it would be possible to rename the column within the Table(…) call, such that I could get rid of the extra CompanyTable thing.

Parameter index out of range with Multiple Join and Optional input parameter

I have an issue with the multiple Join using Spring JdbcTemplate if I need to make optional the input parameters.
This is the scenario.
The SQL table where i must perform the Join are:
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(15),
password VARCHAR(20),
info VARCHAR(30),
active BOOLEAN,
locked BOOLEAN,
lockout_duration INT DEFAULT 0,
lockout_limit DATETIME,
login_attempts INT DEFAULT 0,
PRIMARY KEY(id)
);
CREATE TABLE profiles (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(15),
info VARCHAR(30),
PRIMARY KEY(id)
);
CREATE TABLE profiling(
user_id INT NOT NULL,
profile_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE,
PRIMARY KEY(user_id,profile_id)
);
Where profiling is the table to associate a user with his profile; the profile must be intended as the identification of what actions are permitted to users.
In one my precedent post, i ask how to make optional the sql parameters and I obtained a perfect response, that works and i have always used since then. So, if i need to make this, is put in the where:
WHERE (is null or variabile_name = ?)
And, using jdbctemplate, i write:
jdbcTemplate.query(SQL, new Object[]{variabile_name, variabile_name}, mapper_name);
where, of course, SQL is the String object where i make the Query.
So, i make this also in this case, but i got the error:
java.lang.IllegalStateException: Failed to execute CommandLineRunner
Caused by: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
I report the full method here:
/**
* This metod return the join between users and profiles
* made using the profiling table
*
* #param userID the user id code
* #param profilesID the profile id code
* #return the join list
*/
public List<Profiling> joinWithUsersandProfiles(Integer userID, Integer profileID)
{
//This is the mapper for Profiling
RowMapper<Profiling> profilingMapper = new RowMapper<Profiling>()
{
//This method must be implemented when we use a row mapper
public Profiling mapRow(ResultSet rs, int rowNum) throws SQLException
{
Profiling profiling = new Profiling();
profiling.setUser_id(rs.getInt("profiling.user_id"));
profiling.setProfile_id(rs.getInt("profiling.profile_id"));
//mapping users variabiles
profiling.setUsersId(rs.getInt("users.id"));
profiling.setUsersActive(rs.getBoolean("users.active"));
profiling.setUsersInfo(rs.getString("users.info"));
profiling.setUsersLocked(rs.getBoolean("users.locked"));
profiling.setUsersLockoutDuration(rs.getInt("users.lockout_duration"));
profiling.setUsersLockoutLimit(rs.getTime("users.lockout_limit"));
profiling.setUsersLoginAttempts(rs.getInt("users.login_attempts"));
profiling.setUsersName(rs.getString("users.name"));
profiling.setUsersPassword(rs.getString("users.password"));
//mapping profiles variabiles
profiling.setProfilesId(rs.getInt("profiles.id"));
profiling.setProfilesInfo(rs.getString("profiles.info"));
profiling.setProfilesName(rs.getString("profiles.name"));
return profiling;
}
};
/**
* This is the string that contain the query to obtain the data from profiling table.
* Please note that the notation "? is null or x = ?" means that the x variabile is optional;
* it can be asked as no making the query.
* If we give alla input equals null, it means that we must perform a SQl Select * From table.
*/
String SQL = "SELECT * FROM profiling JOIN users ON profiling.user_id = users.id JOIN profiles ON profiling.profile_id = profiles.id WHERE (is null or profiling.user_id = ?) AND (is null or profiling.profile_id = ?)";
/**
* The list containing the results is obtained using the method query on jdcbtemplate, giving in in input to it the query string, the array of object
* containing the input variabile of the method and the rowmapper implemented.
*/
List<Profiling> theProfilings = jdbcTemplate.query(SQL, new Object[]{userID, userID, profileID, profileID}, profilingMapper);
return theProfilings;
}
I know that the problem is made by the optional variabile. Why? if i try to remove the optional code and pass from:
(is null or variabile_name = ?)
to
variabile_name = ?
The code work perfectly.
So, what's my error here?
Edit: solved myself. I forgot the ? BEFORE the "is null" code. So, passing to:
(? is null or variabile_name = ?)
The code works.

How to use DBNull.Value to check if table column is null; return default value if not null

My current while statement is being used to get all the values from a table (two integer and one string value) and it looks like this:
while (reader.Read())
{
Int16 a = reader.GetInt16("id");
**int b = (reader["nullable_id"] != DBNull.Value) ? Convert.ToInt16(reader["nullable_id"]): 0;**
string c = reader.GetString("string");
Site page = new Site(a, b, c);
list.Add(page);
}
What I am using it to do is to GET all the values in a table. There's a primary key, a foreign key, and a regular string value (a, b, and c respectively). This works fine as is by allowing me to pull the primary and the string value while ignoring the foreign key that currently has null values. However, if I were to alter one of the foreign keys's value to 32 from 'null', the value won't return when I execute the GET method.
So my question is, how do I check whether or not the foreign key is null or not and then, if it is not null, it returns the value stored in the database and if it is null, then it leaves the value as null? I'm relatively new with using DBNull so I may be implementing it incorrectly.
simple change use this
while (reader.Read())
{
Int16 a = Convert.ToInt16(reader["id"]);
int b = (!string.IsNullOrEmpty(Convert.ToString(reader["nullable_id"]))) ? Convert.ToInt16(reader["nullable_id"]): 0;
string c = Convert.ToString(reader["string"]);
Site page = new Site(a, b, c);
list.Add(page);
}

Storing Percentages in MySQL

I'm trying to store a percentage value in a MySQL database but when ever I try and set the value of the percentage column to 100%, I get an "Out of range value" error message.
I am currently using a DECIMAL(5,2) type and I need to be able to store values from 0% up to 100% (with 2dp when the value isn't an integer) ( the values are being calculated in a php script).
All values are fine apart from 100% which triggers the error.
Am I misunderstanding something or is there something else I am missing?
EDIT: The table was created using the following sql
CREATE TABLE overviewtemplate
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(32),
numberOfTests INT NOT NULL DEFAULT 0,
description VARCHAR(255) NOT NULL DEFAULT "Please add a Description",
percentageComplete DECIMAL(5,2),
numberPassed INT NOT NULL DEFAULT 0,
numberFailed INT NOT NULL DEFAULT 0
) ENGINE=MYISAM;
EDIT 2: This is the code of the SQL query
$numberOfPasses = 5;
$numberOfFails = 5;
$percentageComplete = 100.00;
$sqlquery = "UPDATE `overviewtemplate`
SET numberPassed = {$numberOfPasses},
numberFailed = {$numberOfFails},
percentageComplete = {$percentageComplete}
WHERE description = '{$description}'";
EDIT 3: FIXED - Had a syntax error in my table names which meant it was trying to update a wrong table.
With your declaration you should be able to save even 999.99 without trouble. Check if you have set any rule for it not be bigger than 100? If yes then set it to be less than or equal to 100.00
It could be in a trigger.

LINQ to SQL - nullable types in where clause

I have a table with a column that has null values... when I try to query for records where that column IS NULL:
THIS WORKS:
var list = from mt in db.MY_TABLE
where mt.PARENT_KEY == null
select new { mt.NAME };
THIS DOES NOT:
int? id = null;
var list = from mt in db.MY_TABLE
where mt.PARENT_KEY == id
select new { mt.NAME };
Why?
after some more googling, I found the answer:
ref #1
ref #2
int? id = null;
var list = from mt in db.MY_TABLE
where object.Equals(mt.PARENT_KEY, id) //use object.Equals for nullable field
select new { mt.NAME };
This LINQ renders to SQL as follows:
((mt.PARENT_KEY IS NULL) AND (#id IS NULL))
OR ((mt.PARENT_KEY IS NOT NULL) AND (#id IS NOT NULL) AND (mt.PARENT_KEY = #id))
One possibility - if mt.PARENT_KEY is of some other type (e.g. long?) then there will be conversions involved.
It would help if you could show the types involved and the query generated in each case.
EDIT: I think I have an idea...
It could be because SQL and C# have different ideas of what equality means when it comes to null. Try this:
where (mt.PARENT_KEY == id) || (mt.PARENT_KEY == null && id == null)
If this is the case then it's a pretty ugly corner case, but I can understand why it's done that way... if the generated SQL is just using
WHERE PARENT_KEY = #value
then that won't work when value is null - it needs:
WHERE (PARENT_KEY = #value) OR (PARENT_KEY IS NULL AND #value IS NULL)
which is what the latter LINQ query should generate.
Out of interest, why are you selecting with
select new { mt.NAME }
instead of just
select mt.NAME
?) Why would you want a sequence of anonymous types instead of a sequence of strings (or whatever type NAME is?
It's definitely a matter of C# and SQL having different notions of how to compare nulls - the question has been addressed here before:
Compare nullable types in Linq to Sql