В Entity Framework 4 возможно ли смоделировать рекурсивный внешний ключ как один-к-одному? - PullRequest
2 голосов
/ 22 апреля 2011

У меня есть следующая таблица:

CREATE TABLE [dbo].[Exception] (
    [ExceptionID]       INT           IDENTITY (1, 1) NOT NULL,
    [ParentExceptionID] INT           NULL,
    [ApplicationID]     INT           NOT NULL,
    [TypeName]          VARCHAR (256) NOT NULL,
    [Message]           VARCHAR (MAX) NULL,
    [StackTrace]        VARCHAR (MAX) NULL,
    [MachineName]       VARCHAR (128) NULL,
    [UserName]          VARCHAR (64)  NULL,
    [CreatedOn]         DATETIME      NOT NULL
)

Это используется для хранения исключений, которые происходят в приложениях.У меня есть внешний ключ как таковой:

ALTER TABLE [dbo].[Exception] ADD CONSTRAINT [FK_ParentException_Exception] 
FOREIGN KEY ([ParentExceptionID])
REFERENCES [dbo].[Exception] ([ExceptionID])
ON DELETE NO ACTION ON UPDATE NO ACTION;

Почему я разработал его как ParentExceptionID вместо InnerExceptionID, я не могу вам сказать.Это определенно делает его запутанным, моделируя это в EF. Это совершенно произвольно, так как вы можете выразить одни и те же данные в любом случае.

Как вы должны знать, у исключения может быть только одно внутреннее исключение.Однако эта схема позволяет нескольким строкам утверждать, что они имеют один и тот же ParentExceptionID.По логике вещей, этого никогда не происходит, но данные подтверждают это.

Обычно, когда я хочу создать нерекурсивное взаимно-однозначное отношение в моей схеме, я либо использую одно и то же имя столбца первичного ключа в обеих таблицах, либо добавляю уникальный индекс к внешнему ключувторая таблица.

Первая будет выглядеть так:

Table A
    PrimaryKey int
    [...]

Table B
    PrimaryKey int
    [...]

Или другим способом:

Table A
    PrimaryKeyA int
    [...]

Table B
    PrimaryKeyB int
    PrimaryKeyA int unique references A.PrimaryKeyA
    [...]

В любом случае диаграммы SQL и другие инструменты распознают этокак отношения один-к-одному.Entity Framework распознает только первый шаблон, хотя я прочитал.

Моя проблема в том, что с рекурсивным внешним ключом я не могу использовать ни один шаблон.Я, очевидно, не могу иметь первый шаблон, потому что у меня есть только один стол.Я не могу использовать второй, потому что у меня не может быть уникального индекса для столбца внешнего ключа, так как будет более одной строки с NULL ParentExceptionID.Чувак, я бы хотел, чтобы SQL Server позволял уникальному индексу, который не заставлял NULL также быть уникальным!

Когда я пытаюсь создать модель EF из этой схемы, он видит, что несколько строк могут претендовать на один и тот же ParentExceptionIDи это заставляет меня моделировать это как 0..1 -> *.Я не вижу способа остановить это.У моего объекта Exception есть свойство навигации InnerException, и это коллекция.Понятно, что это не то, что мне нужно.Если я пытаюсь изменить кратность ассоциации и установить ее равной 0..1 Я получаю ошибку сборки:

Кратность недопустима в роли 'InnerException' в отношении 'FK_ParentException_Exception'.Поскольку свойства зависимой роли не являются ключевыми свойствами, верхняя граница кратности зависимой роли должна быть *.

Есть ли способ сделать то, что я хочу?Даже если это означает изменение моей схемы, я мог бы рассмотреть это.Сейчас я думаю, что это невозможно.

1 Ответ

0 голосов
/ 22 апреля 2011

Нет, это невозможно отобразить в EF, и даже уникальный индекс по внешнему ключу вам не поможет, потому что в текущей версии EF нет поддержки уникальных ключей.

Единственный способ - отобразить его как один-ко-многим и скрыть реальное свойство навигации, например, внутренний элемент. Вместо этого вы выставите другое свойство (не на диаграмме сущностей) в вашей частичной части класса сущностей, которое позволит определять только одно внутреннее исключение (оно будет просто работать с первым элементом из внутренней коллекции).

Проблемной частью этого решения будет стремление загрузить связанное исключение, поскольку вы не можете загружать пользовательские свойства, а только свойства навигации.

...