SubSonic не распознает внешние ключи SQLite - PullRequest
3 голосов
/ 24 августа 2010

Я использую SubSonic 3.0.0.3, и я не могу получить файлы ActiveRecord .tt для распознавания и генерации кода для внешних ключей и отношений в моей базе данных SQLite.

Я думаю, что он генерирует все остальное просто отлично, но после просмотра других фрагментов в Интернете, похоже, должно быть больше сгенерированного кода, чем просто отдельные классы в ActiveRecord.cs и Structs.cs для каждой из моих таблиц. Если заглянуть внутрь Structs.cs, IsForeignKey - это всегда false для каждого столбца, даже для которого у меня есть внешний ключ. Кроме того, каждая Foreign Keys область пуста в каждом сгенерированном классе ActiveRecord.

Я использую VS2008 со ссылками на SubSonic 3.0.0.3, System.Data.SQLite 1.0.66.0 и System.Data.SQLite.Linq 2.0.38.0 в моем проекте. Я создал базу данных с помощью SQLite Expert Personal 3.1.0.2076. Я сделал несколько фиктивных таблиц, чтобы попытаться проверить, как SubSonic справляется с одним: много и много: много отношений. Вот DDL SQLite Expert выплевывает для моей маленькой базы данных:

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]));

Я знаю, что внешние ключи включены и работают в базе данных - эксперт SQLite говорит, что они включены, и когда я меняю данные в одном месте, например PersonID PersonID, он действительно изменяет этот PersonID в таблицах Dog и GroupPersons. Я попытался повторно добавить базу данных в проект, «запустить пользовательский инструмент», чтобы снова запустить файлы .tt, и даже удалить их и добавить их обратно. Я могу получить простой проект для сборки, который выполняет простые запросы и вставки, однако я только что попытался изменить первичный ключ одного Person, Dog или Group и x.Save (), но System.Data.SQLite вызвал исключение для все три, говоря SQLite error near "WHERE":syntax error. в Save ().

Любые предложения о том, что я должен попытаться сделать дальше?

Ответы [ 2 ]

5 голосов
/ 26 августа 2010

Кажется, что атрибут FKTables для каждой таблицы не назначен в файле "SQLite.ttinclude". Поэтому я добавил несколько строк кода и сумел сгенерировать код внешнего ключа:

После строки 16 (var schema = conn.GetSchema ("COLUMNS");) вставить:

var schemaForeignKeys = conn.GetSchema("FOREIGNKEYS");

После строки 29 (tbl.Name = row ["TABLE_NAME"]. ToString ();) вставить:

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);
}

И после строки 53 (col.IsNullable = row ["IS_NULLABLE"]. ToString () == "True";) вставить:

col.IsForeignKey = tbl.FKTables.Any(x => x.ThisColumn == col.Name);

Это для генерации кода внешнего ключа.

Кроме того, возможно, у вас возникла проблема, когда вам нужно удалить запись, столбец которой должен быть внешним ключом в другой таблице? Например : Персона (Id, Имя) Собака (Id, #PersonId) Если вы установили действие удаления внешнего ключа #PersonId на «SET TO NULL», это не будет работать, поскольку поддержка внешнего ключа отключена по умолчанию в SQLite 3.6.23.1 (версия, используемая Data.SQLite 1.0.66.0). Чтобы включить поддержку внешнего ключа, необходимо выполнить эту команду для каждого соединения:

PRAGMA foreign_keys = ON;

Теперь это не поддерживается Data.SQLite, но будет (в версии 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 ).

Так что вам придется ждать релиза или вы можете (как и я) скачать исходный код Data.SQLite и скомпилировать последнюю версию. Это прекрасно работает для меня.

Удачи. И извините за мой английский:)

1 голос
/ 24 августа 2010

Я пытаюсь объяснить это.Кажется, есть две проблемы:

  • Дозвуковой не распознает ваши внешние ключи
  • Функция x.Save() отправляет это сообщение об ошибке.

SQLiteбудет обеспечивать ссылочную целостность самостоятельно, поэтому, пока Subsonic не видит внешние ссылки, SQLite делает, и именно поэтому ваши обновления проходят.Subsonic не управляет SQLite, он управляет собой, и это нормально.

Я пытаюсь узнать, что SubSonic означает , а делает .Между тем, у меня есть такая гипотеза: определения таблиц не анализируются правильно.Если x.Save() использует автоматически сгенерированный SQL, это может означать, что две проблемы на самом деле просто одна.

Чтобы проверить (или опровергнуть) эту гипотезу, не могли бы вы попытаться определить таблицы таким образом, задавая внешние ключи какатрибуты таблицы, а не атрибуты конкретных полей:

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]));
...