I use the MS Sync Framework to sync my SQL Server instance with a local SQL CE file to make it possible working offline with my Windows app.
I use GUIDs as keys. On my table I have a unique index on 2 columns: user_id and setting_id:
usersettings table
------------------
id PK -> I also tried it without this column. Same result
user_id FK
setting_id FK
value
Now I do the following:
I create a new record in this table in both databases - SQL Server and SQL CE with the same user_id and setting_id.
This should work and merge the data together since this can happen in real life. But I get an error when syncing saying the unique key constraint led to an error. The key pair already exists in the table.
A duplicate value cannot be inserted into a unique index. [ Table name = user_settings,Constraint name = unique_userid_settingid ]
Why can't MS sync handle that? It should not try to insert the key pair again. It should update the value if needed.
The issue is if you add the same key pair to different copies of the table, they get different IDs (GUIDs) as primary keys in this usersettings table.
As this is simply a many-to-many table between Users and Settings, there is no need to have that ID as a PK (or even a column at all).
Instead, just use a concatenated key of the two FKs e.g.,
CREATE TABLE [dbo].[usersettings](
[user_id] [UNIQUEIDENTIFIER] NOT NULL,
[setting_id] [UNIQUEIDENTIFIER] NOT NULL,
[value] [varchar](50) NOT NULL,
CONSTRAINT [PK_usersettings] PRIMARY KEY CLUSTERED ([user_id] ASC, [setting_id] ASC) );
Of course, include appropriate field settings (e.g., if you use VARCHARs to store the IDs) and relevant FKs.
As the rows inserted should now be identical on the two copies, it should merge fine.
If you must have a single column as a unique identifier for the table, you could make it meaningful e.g.,
the PK (ID) becomes a varchar (72)
it gets filled with CONCAT(user_ID, setting_id)
As the User_ID and Setting_ID are FKs, you should already have them generated so concatenating them should be easy enough.
Do you get the error during sync, then it should appear as a conflict, that you must solve in code.
https://learn.microsoft.com/en-us/previous-versions/sql/synchronization/sync-framework-2.0/bb734542(v=sql.105)
I also see this in the manual: By default, the following objects are not copied to the client database: FOREIGN KEY constraints, UNIQUE constraints, DEFAULT constraints, and the SQL Server ROWGUIDCOL property. This indicates poor support for your scenario
I suggest you remove the unique constraint from the device table.
Related
A tale of three tables: using Entity Framework 6, I need a user-editable table Disallow to store conflicts between rows of another table Option of type Technology.
Like this:
Technology:
ID, PK, [int], not null
Description, nvarchar(40), not null
Option:
ID, PK, [int], not null
Name, nvarchar(20), not null
ADD CONSTRAINT (FK_Tech) FOREIGN KEY [ID] REFERENCES [Technology] (ID)
Disallow:
ID1, [int], not null
ID2, [int], not null
PRIMARY KEY (ID1, ID2) ASC
ADD CONSTRAINT [FK_Valid1] FOREIGN KEY [ID1] REFERENCES [Option] (ID)
ADD CONSTRAING (FK_Valid2) FOREIGN KEY [ID2] REFERENCES [Option] (ID)
As I understand it, after importing the database into the model the user should be able to add records from the EF model so that e can specify that when choosing technology options, it should be disallowed to choose two particular options together.
I have spent much time looking for help on using multiple foreign keys into a single table and was able to create the table successfully in SQL Server and I think I understand the issues there.
But when I attempt to import into EF, an association is shown, on the Options table, but nothing else. How can I add rows if there is no mapping to the table? And then I found a link telling me that there is no way to reference a foreign key. So I added two additional fields, but even after numerous attempts -- following the advice of many links on THAT topic -- failed to bring the table into the model. How can I ensure (1) that the IDs added to the Disallow table are found in Option, and (2) still reference them in EF?
Or perhaps better said, how can I accomplish what I want: rows of conflicts that my code will use to limit the selection of options?
I created in my application a dataclasses context and want to insert in my database some entries via LINQ but it says
Can't perform Create, Update, or Delete operations on
'Table(discipline)' because it has no primary key.
But I already marked a column in the designer as identity column to true;
Can anyone please help?
Setting a column as IDENTITY doesn't mean that it is also the PRIMARY KEY of your table.
You need to set it explicitily using SSMS interface of through a sql statement
You can set it when creating the table:
CREATE TABLE Nations
(
NationID int IDENTITY(1,1),
Name varchar(255) NOT NULL,
CapitalCity varchar(255)
PRIMARY KEY (NationID)
)
or using the ALTER TABLE statement
ALTER TABLE Nations ADD PRIMARY KEY (NationID)
I want to implement a patients data base for our software, and have an issue with the foreign key statement. I am using the latest SQLite DLLs, with C#.
When I try to run below code:
dbConnection = "Data Source=SQLiteMyDatabase.db;foreign keys=true;";
if (connections == 0)
{
cnn = new SQLiteConnection(dbConnection);
cnn.Open();
this.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS patients ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name VARCHAR(100) NOT NULL;");
this.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS images ( FOREIGN KEY (patientID) REFERENCES patients(id), nameRed VARCHAR(20) NOT NULL PRIMARY KEY;");
}
I get the error:
SQLite error near "FOREIGN": syntax error
Why does this happen?
In order to create a foreign key, you must first create the column:
CREATE TABLE IF NOT EXISTS images (
nameRed VARCHAR(20) NOT NULL PRIMARY KEY,
patientID INT,
FOREIGN KEY (patientID) REFERENCES patients(id)
);
Please note:
I moved the primary key column (nameRed) first in the list of columns created, but that's just convention. It could go second.
You use the data type VARCHAR and SQlite will accept that, but be aware that it gets mapped to type TEXT, the maximum length will be ignored, and you will be able to store other data types in the column. SQLite is a bit funny when it comes to data types (it has a very well thought-out system but it's quite different from most other SQL databases).
To make things more confusing, you are allowed to declare the PRIMARY KEY as a property of the column (although you can also do it after the list of columns as with the FOREIGN KEY).
I am working with PostgreSql DB using Entity Framework:
When I add new item into DB it generates strange code:
INSERT INTO (SELECT "person_contact"."person_id" AS "person_id",
"person_contact"."contact_id" AS "contact_id"
FROM "public"."person_contact" AS "person_contact")
("person_id","contact_id")
VALUES (cast(141792 as int8),cast(289406040 as int8))
So it add
SELECT "person_contact"."person_id" AS "person_id",
"person_contact"."contact_id" AS "contact_id"
FROM "public"."person_contact" AS "person_contact"
instead of table name "public"."person_contact"
How to resolve this Entity Framework bug ???
UPD: Same issue when I try to delete "person_contact" entry. In delete statement instead of table name - select query.
There are several ways to try and fix this:
Firstly, it could be that your model has become corrupt. You could try deleting the model and recreating it. Also see my answer to this question: SQL Server foreign keys messing with entity framework model
Secondly, you say that it only happens with this table. Is there anything special about this table.
Thirdly, you could try a different .net connector for ProgressSQL, see: http://www.devart.com/dotconnect/entityframework.html
These are listed in the order that I would try them.
Most likely you forgot to create primary key on this table.
I've had the same problem and the solution in my case was very simple. The problem was that I had a column named "id", but I forgot to make it Primary Key. The moment I set it as Primary Key everything was OK.
It is very strange, because EF, normaly won't import table without primary key, but when you have column named "id" it assumes that it is a primary key.
The structure of my table was:
*DROP TABLE IF EXISTS "public"."fact_season_tickets";
CREATE TABLE "public"."fact_season_tickets" (
"id" int8 DEFAULT nextval('fact_season_tickets_id_seq'::regclass) NOT NULL,
"season_ticket_id" int8 NOT NULL,
"date_key" int4 NOT NULL,
"station_id" int4 NOT NULL,
"amount" numeric(18,2) DEFAULT 0 NOT NULL,
"status" int4 NOT NULL
)
WITH (OIDS=FALSE)*
The generated by NpgSql INSERT statement was:
*INSERT INTO (SELECT "fact_season_tickets"."id",
"fact_season_tickets"."season_ticket_id",+
"fact_season_tickets"."date_key",
"fact_season_tickets"."station_id",
"fact_season_tickets"."amount",
"fact_season_tickets"."status"
FROM "public"."fact_season_tickets" AS "fact_season_tickets")
("season_ticket_id","date_key","station_id","amount","status")
VALUES (510::int8,20150630,2,18.00::numeric,1)
RETURNING "id"*
The solution was just creating a primary key:
*ALTER TABLE "public"."fact_season_tickets" ADD PRIMARY KEY ("id");*
I'm using SubSonic 3.0.0.3 and I can't seem to get the ActiveRecord .tt files to recognize and generate code for the foreign keys and relationships in my SQLite database.
I think it generates everything else just fine, but after looking at other snippets online it looks like there should be more generated code than just single classes in ActiveRecord.cs and Structs.cs for each of my tables. Looking inside Structs.cs, IsForeignKey is always false for every column, even the ones I have a foreign key defined for. Additionally, each Foreign Keys region is empty within each generated ActiveRecord class.
I'm using VS2008 with references to SubSonic 3.0.0.3, System.Data.SQLite 1.0.66.0, and System.Data.SQLite.Linq 2.0.38.0 in my project. I created the database using SQLite Expert Personal 3.1.0.2076. I made some dummy tables to try to test out how SubSonic handles one:many and many:many relationships. Here's the DDL SQLite Expert spits out for my small database:
CREATE TABLE [Person] (
[PersonID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[PersonName] TEXT NOT NULL,
[PersonAge] INT NOT NULL
);
CREATE TABLE [Group] (
[GroupID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[GroupName] TEXT NOT NULL,
[GroupDescription] TEXT NOT NULL
);
CREATE TABLE [Dog] (
[DogID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[PersonID] INT NOT NULL CONSTRAINT [DogPersonFK] REFERENCES [Person]([PersonID]) ON DELETE CASCADE ON UPDATE CASCADE,
[DogName] TEXT NOT NULL);
CREATE TABLE [GroupPersons] (
[GroupID] INTEGER NOT NULL CONSTRAINT [GroupPersonToGroupFK] REFERENCES [Group]([GroupID]) ON DELETE CASCADE ON UPDATE CASCADE,
[PersonID] INTEGER NOT NULL CONSTRAINT [GroupPersonToPersonFK] REFERENCES [Person]([PersonID]) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT [sqlite_autoindex_GroupPersons_1] PRIMARY KEY ([GroupID], [PersonID]));
I know foreign keys are enabled and work in the database - SQLite Expert says they're on and when I change data in one place, like Person's PersonID, it does indeed change that PersonID in the Dog and GroupPersons tables. I've tried re-adding the database to the project, 'running custom tool' to get the .tt files to execute again, and even deleting them and adding them back. I can get a simple project to build that perform simple querying and insertions, however I tried just now to change the primary key of a single Person, Dog, or Group and x.Save() but System.Data.SQLite threw an exception for all three, saying SQLite error near "WHERE":syntax error. at the Save().
Any suggestions for what I should try to do next?
It seems that the FKTables attribute for each table is not assigned in the file "SQLite.ttinclude". So i add some lines of code and managed to generate foreign key code :
After line 16 (var schema = conn.GetSchema("COLUMNS");), insert :
var schemaForeignKeys = conn.GetSchema("FOREIGNKEYS");
After line 29 (tbl.Name = row["TABLE_NAME"].ToString();), insert :
tbl.FKTables = new List<FKTable>();
var foreignKeyTables = schemaForeignKeys.Select("TABLE_NAME='" + tbl.Name + "'");
foreach (var foreignKeyTable in foreignKeyTables) {
FKTable foreignKey = new FKTable();
foreignKey.ThisTable = foreignKeyTable["TABLE_NAME"].ToString();
foreignKey.ThisColumn = foreignKeyTable["FKEY_FROM_COLUMN"].ToString();
foreignKey.OtherTable = foreignKeyTable["FKEY_TO_TABLE"].ToString();
foreignKey.OtherColumn = foreignKeyTable["FKEY_TO_COLUMN"].ToString();
foreignKey.OtherClass = CleanUp(foreignKey.OtherTable);
foreignKey.OtherQueryable = foreignKey.OtherClass;
tbl.FKTables.Add(foreignKey);
}
And after line 53 (col.IsNullable=row["IS_NULLABLE"].ToString()=="True";), insert :
col.IsForeignKey = tbl.FKTables.Any(x => x.ThisColumn == col.Name);
This is for generate the foreign key code.
Moreover, you have maybe encounter a problem when you have to delete a record which has a column to be a foreign key in an other table ? For exemple :
Person(Id, Name)
Dog(Id, #PersonId)
If you have set the #PersonId foreign key on-delete action to "SET TO NULL", this won't work because foreign key support is disabled by default in SQLite 3.6.23.1 (version used by Data.SQLite 1.0.66.0).
To enable foreign key support, you have to execute this command with each connection :
PRAGMA foreign_keys = ON;
Now, this is not supported by Data.SQLite, but it will (in version 1.0.67.0, http://sqlite-dotnet2.cvs.sourceforge.net/viewvc/sqlite-dotnet2/SQLite.NET/System.Data.SQLite/SQLiteConnection.cs?r1=1.80&r2=1.81).
So you have to wait for the release or you can (like me) download the Data.SQLite source and compile the last version. It work great for me.
Good luck.
And sorry for my english :)
I'm trying to reason this. There seems to be two issues at hand:
Subsonic not recognising your foreign keys
The x.Save() function sending that error message.
SQLite will be enforcing referential integrity on its own, so while Subsonic does not see the foreign references, SQLite does, and that's why your updates go through. Subsonic does not drive SQLite, it is driving itself, which is fine.
I'm attempting to learn what SubSonic is and does. In the mean time, I have this hypothesis: the table definitions are not parsed correctly. If x.Save() is uses automatically generated SQL, it could be that the two issues are really just one.
To validate (or invalidate) this hypothesis, could you try defining the tables thus, giving the foreign keys as table attributes, not attributes of specific fields:
CREATE TABLE [Dog] (
[DogID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[PersonID] INTEGER NOT NULL,
[DogName] TEXT NOT NULL,
FOREIGN KEY ([PersonID]) REFERENCES [Person]([PersonID]) ON DELETE CASCADE ON UPDATE CASCADE);
CREATE TABLE [GroupPersons] (
[GroupID] INTEGER NOT NULL,
[PersonID] INTEGER NOT NULL,
FOREIGN KEY ([GroupID]) REFERENCES [Group]([GroupID]) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY ([PersonID]) REFERENCES [Person]([PersonID]) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY ([GroupID], [PersonID]));