Entity Framework 4.1 - отношения между неключевыми столбцами - PullRequest
13 голосов
/ 24 августа 2011

У меня есть 2 связанных объекта, но у устаревшей схемы sql по существу есть 2 ключевых столбца для одной и той же таблицы (не ключ с 2 столбцами: см. Ниже). Мне нужно создать отношение обратно к столбцу «ключ искусственного». Есть ли способ сделать это декларативно в Entity Framework 4.1?

Public Class Client
    Inherits ModelBase

    <Key(), Required()>
    Public Property ClientID As Decimal

    <Required(), StringLength(50)>
    Public Property ClientCode As String

    ........


Public Class ClientLocation
    Inherits ModelBase

    ........

    <Required(), StringLength(50)>
    Public Property ClientCode As String

    ........

    <ForeignKey("ClientCode")>
    Public Overridable Property Client As Clients.Client

И ошибка, которую я получаю:

* Одна или несколько ошибок проверки были обнаружены во время генерации модели: System.Data.Edm.EdmAssociationConstraint :: Типы всех свойства в зависимой роли ссылочного ограничения должны быть так же, как соответствующие типы свойств в главной роли. Тип свойства 'ClientCode' для объекта 'ClientLocation' не имеет соответствовать типу свойства «ClientID» объекта «Client» в ссылочное ограничение "ClientLocation_Client". *

Поскольку он думает, что я пытаюсь отобразить ClientLocation.ClientCode> Client.ClientID , когда я действительно пытаюсь отобразить ClientLocation.ClientCode> Client.ClientCode ...

Есть мысли?

Спасибо!

Ответы [ 4 ]

3 голосов
/ 25 августа 2011

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

2 голосов
/ 30 сентября 2011

Даже если это невозможно, вы все равно можете объединить две таблицы, используя запрос LINQ, например, так (C #) (см. Также вопрос ).

var result = from a in ctx.Client
             join b in ctx.ClientLocation
             on a.ClientCode equals b.ClientCode
             select new { Client = a, Location = b };

Вы толькоотсутствует навигационное свойство Client.ClientLocation и ClientLocation.Client.Это немного сложнее сделать таким образом, но, тем не менее, это возможно.

Если вы хотите расширить схему SQL, вы можете добавить еще одну таблицу, например ClientLocationClient, которая действует как таблица M: N с внешними ключами.для клиента и ClientLocation, а также в качестве составного ключа.Затем вы можете перемещаться следующим образом (C #)

var client = myClientLocation.ClientLocationClients.First().Client; // there's only one

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

0 голосов
/ 28 сентября 2011

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

Пример кода:

[ForeignKey()]
[Association("SomeNameForAssociation","TheKeyInThisEntity","TheKeyOnTheAssociationTargetEntity")]
public virtual Examination Examination { get; set; }

И если я понимаю ваш вопрос, ваш код должен измениться на:

Public Class Client   
    Inherits ModelBase   

    <Key(), Required()>   
    Public Property ClientID As Decimal   

    <Required(), StringLength(50)>   
    Public Property ClientCode As String   

    ........   


Public Class ClientLocation   
    Inherits ModelBase   

    ........   

    <Required(), StringLength(50)>   
    Public Property ClientCode As String   

    ........   

    <ForeignKey("ClientCode")> 
    <Association("ClientClientCodes","ClientCode","ClientCode")>
    Public Overridable Property Client As Clients.Client  

Первый «ClientCode»: имя ключевого столбца в ClientCode. Второй «ClientCode»: имя ключевого столбца в ClientCode, который вы хотите использовать.

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

0 голосов
/ 23 сентября 2011

(Это только приложение к ответу Ладислава, согласие и щедрость не должны идти на мой ответ.)

Я был бы удивлен, если такая функция будет когда-либо реализована в EF. Зачем? Потому что вы даже не можете создать такие отношения в реляционной базе данных. Отношение внешнего ключа в реляционной БД (по крайней мере, SQL Server и, вероятно, большинство или все остальные) требует, чтобы главной стороной был столбец, который является либо первичным ключом, либо имеет ограничение уникального ключа . Это имеет смысл, поскольку предполагается, что внешний ключ ссылается на одну уникальную строку в главной таблице.

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

Что вы ожидаете, если значение в целевом столбце основной таблицы не является уникальным? Требуется ли исключение, когда вы, например, пытаетесь загрузить ClientLocation.Client - «Невозможно загрузить свойство навигации« Клиент », поскольку внешний ключ не ссылается на уникальную цель» или предупреждение «Загрузил ли клиент, но есть другой, не могу гарантировать, что я загрузил тот, который вы хотели» или что-то в этом роде?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...