Подтвердить что ты не робот

Entity Framework 4.1 - Отношения между несимвольными столбцами

У меня есть два объекта, которые связаны друг с другом, но унаследованная схема sql по существу имеет 2 ключевых столбца для одной и той же таблицы (а не 2-столбцовый ключ: см. ниже). Мне нужно создать отношение к столбцу "faux key". Есть ли способ сделать это декларативно в 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" на объекте "Клиент" в референтное ограничение "ClientLocation_Client". *

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

Любые мысли?

Спасибо!

4b9b3361

Ответ 1

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

Ответ 2

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

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 с внешними ключами как для Client, так и для ClientLocation, а вторая - как составной. Затем вы можете перемещаться так (С#)

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

Некоторый код выглядит следующим образом:

[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, который вы хотите использовать.

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