I'm facing a trouble with my application: I have a constraint on my database where trip_id + trip_level_id must be unique.
Now, this is at database level (no validation), if I try to add an item with those fields already present in db, I receive a "constraintexception".
The problem is:
The constraintexception is only relative to SQlite3, while I require something for "all database", expecially I'll use mysql in production while sqlite3 in development.
After the constraint exception, mongrel shutdown and this is definitely not what I want. I want to send the user a message "constraint exception happened" and just don't add the item, the user need to go back and add an item that is correct.
How can I convert all those exception into errors that activerecords should fetch for me, if possible (this should be the greatest solution)?
Otherwise, how to declare a validation method that ensures that for those 2 columns, value should be unique?
Edit 1: I just noticed I can't rescue SQLite3::ConstraintException on save method, at least not if I'm using just the Exception class. I think I must declare a validation, but it feels a bit redundant if already exists in database.
Edit 2: These seems to talk about the problem: https://rails.lighthouseapp.com/projects/8994/tickets/2419-raise-specific-exceptions-for-violated-database-constraints however it looks like they didn't apply it, but the post is really old (3 years)
Reading around, I discovered that database constraints aren't very well implemented in activerecord, and using a validates_uniqueness_of with a scope will solve my problem.
I definitely don't like the solution for optimization, but I couldn't find a way to effectively rescue the exception in my create and update methods, so actually I solved in this way.
Related
I'm working on implementing and designing my first database and have a lot of columns with names and addresses and the like.
It seems logical to place a CHECK constraint on these columns so that the DB only accepts values from an alphanumeric range (disallowing any special characters).
I am using MySQL which, as far as I can tell doesn't support user defined types, is there an easy way to do this?
It seems worth while to prevent bad data from entering the DB, but should this complex checking be offloaded to the application instead?
You can't do it with a CHECK constraint if you're using mysql (question is tagged wth mysql, so I presume this is the case) - mysql doesn't support check constraints. They are allowed in the syntax (to be compatible with DDL from other databases), but are otherwise ignored.
You could add a trigger to the table that fires on insert and update, that checks the data for compliance, but if you find a problem there's no way to raise an exception from a mysql stored proc.
I have used a workaround of hitting a table that doesn't exist, but has a name that conveys the meaning you want, eg
update invalid_characters set col1 = 1;
and hope that the person reading the "table invalid_characters does not exist" message gets the idea.
There are several settings that allows you to change how MySQL handles certain situation (but those aren't enough) for your case.
I would stick with data validation on application side but if you need validation on database side, you have two options:
CREATE PROCEDURE that would validate and insert data, do nothing or raise error by calling SIGNAL
CREATE TRIGGER ... BEFORE INSERT which would validate data and stop insert like suggested in this stackoverflow answer
Our developer has a linq-2-sql project that talks to my database. The database is involved in merge replication. It has been in use for some time and was working fine. A recent table was added to the schema and now is causing problems when new records are added.
The user get's an error message stating that the index related to the guid that merge replication automatically creates is violating a unique constraint.
From what I can tell the table isn't any different than others that are involved. I have recreated the entire replication publication/subscription model from scratch and everything continues to work but that one table.
Anyone have any ideas? The guid being created appears as 00000000-0000-0000-0000-000000000000 which would explain why it's a duplicate. Why is a valid guid not being created by linq?
Did you use "new Guid()" somewhere in your code base when what you meant was "Guid.NewGuid()"?
I had faced the similar problem. As Mark has mentioned in the comment, the Guid() needs to be properly used.
Guid asm = new Guid(); // gives 00000000-0000-0000-0000-000000000000
Instead use
Guid asm = Guid.NewGuid();
When using Linq-To-SQL, make sure the IsDbGenerated property is true and the Database actually is setup to create an ID (by using newid() as the default value).
Otherwise, make sure the .net code is actually generating IDs.
What we discovered while researching your suggestions was that this particular table was the only table that included the guid field at all in the DBML class. All the other tables had been added to the DBML prior to publishing the database for merge replication (hence their respective guid fields were not included in the DBML).
So, I manually deleted the guid field from the problem table in the DBML and the problem went away. The problem was in fact caused by LINQ not creating the guid as it should in the generated classes.
In this case it was easiest to simply leave guid creation to the publication triggers and newid() default value as established in SQL. (it's still in the database, just not the dbml)
Nothing in the application uses those guid fields... it's purely for SQL to manage the merge replication scheme we've implemented - so removing from the DBML was the easiest.
I would like to implement a custom database initialization strategy so that I can:
generate the database if not exists
if model change create only new tables
if model change create only new fields without dropping the table and losing the data.
Thanks in advance
You need to implement IDatabaseInitializer interface.
Eg
public class MyInitializer : IDatabaseInitializer<MyDbContext>
{
public void InitializeDatabase(MyDbContext context)
{
//your logic here
}
}
And then set your initializer at your application startup
Database.SetInitializer<ProductCatalog>(new MyInitializer());
Here's an example
You will have to manually execute commands to alter the database.
context.ObjectContext.ExecuteStoreCommand("ALTER TABLE dbo.MyTable ADD NewColumn VARCHAR(20) NULL");
You can use a tool like SQL Compare to script changes.
There is a reason why this doesn't exist yet. It is very complex and moreover IDatabaseInitializer interface is not very prepared for such that (there is no way to make such initialization database agnostic). Your question is "too broad" to be answered to your satisfaction. With your reaction to #Eranga's correct answer you simply expect that somebody will tell you step by step how to do that but we will not - that would mean we will write the initializer for you.
What you need to do what you want?
You must have very good knowledge of SQL Server. You must know how does SQL server store information about database, tables, columns and relations = you must understand sys views and you must know how to query them to get data about current database structure.
You must have very good knowledge of EF. You must know how does EF store mapping information. You must be able to explore metadata get information about expected tables, columns and relations.
Once you have old database description and new database description you must be able to write a code which will correctly explore changes and create SQL DDL commands for changing your database. Even this look like the simplest part of the whole process this is actually the hardest one because there are many other internal rules in SQL server which cannot be violated by your commands. Sometimes you really need to drop table to make your changes and if you don't want to lose data you must first push them to temporary table and after recreating table you must push them back. Sometimes you are doing changes in constraints which can require temporarily turning constrains off, etc. There is good reason why tools which do this on SQL level (comparing two databases) are probably all commercial.
Even ADO.NET team doesn't implemented this and they will not implement it in the future. Instead they are working on something called migrations.
Edit:
That is true that ObjectContext can return you script for database creation - that is exactly what default initializers are using. But how it could help you? Are you going to parse that script to see what changed? Are you going to execute that script in another connection to use the same code as for current database to see its structure?
Yes you can create a new database, move data from the old database to a new one, delete the old one and rename a new one but that is the most stupid solution you can ever imagine and no database administrator will ever allow that. Even this solution still requires analysis of changes to create correct data transfer scripts.
Automatic upgrade is a wrong way. You should always prepare upgrade script manually with help of some tools, test it and after that execute it manually or as part of some installation script / package. You must also backup your database before you are going to do any changes.
The best way to achieve this is probably with migrations:
http://nuget.org/List/Packages/EntityFramework.SqlMigrations
Good blog posts here and here.
How to determine connection state of Perl DBI database handler(is connection opend)? Something like .NET SqlConnection.State == Open. May be something like
defined($dbh->do("some nop sql"))
but can't find sql nop statement to use.
You can ask you database handle if it is connected by calling
$dbh->ping();
Some DB Drivers don't implement ping but DBD::mysql does. An alternative is to run an empty select like select 1 for MySQL. I'm assuming MySQL since that is how your question is tagged. Other databases will have slightly different answers.
There are two parts to this answer.
The first answer is the {Active} field. perldoc DBI says:
ATTRIBUTES COMMON TO ALL HANDLES
These attributes are common to all
types of DBI handles.
[...]
"Active" (boolean, read‐only)
The "Active" attribute is true if the
handle object is "active". This is
rarely used in applications. The exact
meaning of active is somewhat vague at
the moment. For a database handle it
typically means that the handle is
connected to a database
("$dbh−>disconnect" sets "Active"
off).
That's probably what you want to check.
The second answer is that, while you can call ping(), or check the result of SELECT 1, there's not much point. That will indeed tell you if the database handle is connected at the time of that check. But what you really want to know is whether the database handle is connected when you do what you're about to do next, right? And there's always a chance that the connection will fail between your check and whatever it is you actually want to do. So a true result from either of those isn't a guarantee of anything.
If you're doing status monitoring, then a ping() or SELECT 1 will do fine. In an application, though, don't check a dbh's validity before doing something. Just connect, and use the dbh you get back, and do proper error-checking at every step. There's no substitute for correctly checking for errors.
The ping method - though what it does is going to be database driver dependent.
there's also $dbh->state()
but yeah proper error-checking at every call is more certain.
I get an SqlDateTime overflow error (Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.) when doing an INSERT using an Linq DataContext connected to SQL Server database when I do the SubmitChanges().
When I use the debugger the date value is correct. Even if I temporary update the code to set the date value to DateTime.Now it will not do the insert.
Did anybody found a work-around for this behaviour? Maybe there is a way to check what SQL the datacontext submits to the database.
Do you have the field set as autogenerated in the designer? If that's not the problem, I'd suggest setting up logging of the data context actions to the console and checking the actual SQL generated to make sure that it's inserting that column, then trace backward to find the problem.
context.Log = Console.Out;
FWIW, I often set my "CreatedTime" and "LastUpdatedTime" columns up as autogenerated (and readonly) in the designer and give them a suitable default or use a DB trigger to set the value on insert or update. When you set it up as autogenerated, it won't include it in the insert/update even if modified. If the column doesn't allow nulls, then you need to supply an alternate means of setting the value, thus the default constraint and/or trigger.
Are you sure you're looking at the right Date column? Happened to me once, and the error turned out to be caused by another non-nullable Date column that wasn't set before submitting.
I came across this recently.
The error may as well say "something's preventing the save!". Because in my case, it was not the DateTime value that was the problem.
I thought I was passing a value in for the primary key, and what was arriving was "null". Being the key, it can't be null - and so my problem was completely somewhere else. By resolving the null, the problem disappeared.
We all hate misleading errors - and this is one of them.
Lastly, as a suggestion... If you do find conversion of dates a problem, then don't use dates at all! .NET's DateTime class supports the "Ticks" value. It can also instantiate a new DateTime(ticks); too. The only Gotcha with that one, is the implementation of ticks in Javascript has a different starting point in history. So you might want a conversion between ticks if you ever tried getting DateTimes from c# to Javascript.
I suggest you change your project's Target Framework. Maybe SQL Server is newer than .Net Framework. I see the same your issue:
My project's Target Framework is 3.5.
SQL Server is 2012
And then I change to 4.0. The issue is solved.
Bottom line: watch the order of your calls to SubmitChanges() and ensure that all objects that would be "submitted" are actually ready to be submitted. This often happens to me when I'm in the middle of setting the attributes of new LINQ object (e.g, the ".FirstName" of new "tblContact"), and then some conditional logic requires the creation of a separate, related record (e.g., a new "tblAddress" record), so the code goes to create the "tblAddress" and tries to SubmitChanges() on saving that record, but that SubmitChanges() then also tries to insert the unfinished "tblContact" record, which maybe doesn't yet have a required "BirthDate" field value set. Thus, the exception looks to occur when I'm inserting the "tblAddress" object/record, but actually refers to the lack of "BirthDate" for the "tblContact" object/record.