Исключение сопоставления фрагментов с таблицей на иерархию (Entity Framework 4) - PullRequest
1 голос
/ 13 января 2011

Если у меня есть таблицы SQL Server, подобные этим:

Location
----------
LocationId int PK 
Field1 int
Field2 int
etc

Score
------------------------------------
LocationId int PK, FK
IsSingleLevel bit PK (discriminator)
Field1 int
Field2 int
etc

Технически это отображается как Location 1..0 .. * Score, но с PK LocationId / IsSingleLevel, это Location 1..0..2.

Когда я перетаскиваю это на EDMX, все настраиваю как положено (абстрактная сущность, удаляем дискриминатор из базовой сущности и т. Д.).

EF дает эту ошибку тривремена (один для базового объекта и один для двух производных объектов):

Ошибка 6 Ошибка 3025: проблема при отображении фрагментов, начиная со строки 2146: необходимо указать отображение для всех ключевых свойств (LocationScore.LocationId), LocationScore.IsSingleLevelScore) таблицы LocationScore.

Я последовал примеру здесь .

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

У меня не может быть LocationId в качестве единственного поля в ПК, потому что тогда местоположение может иметь только 1 балл,мне нужно это иметьдва балла (один единственный уровень, один общий).

Конечным результатом является то, что я хочу иметь возможность сделать это:

Locations.Include("LocationOverallScore").Single();
Locations.Include("LocationSingleLevelScore").Single();

Где LocationOverallScore и LocationSingleLevelScore являются производными объектамииз базы LocationScore (абстрактная сущность).

Разве ТПХ не является правильным дизайном здесь?Мой дизайн базы данных неправильный?Цель состоит в том, чтобы я не хотел иметь две физические таблицы для разных оценок - поскольку таблица огромна, и я не хочу повторять столбцы.

Есть два возможных обходных пути, о которых я могу подумать:

1 - Создайте представление (LocationScore), в котором UNION две таблицы (поэтому он будет возвращать 2 строки на LocationId), но я все еще не могуне думаю, что я могу "ТПХ" это.Я не хочу вручную выполнять JOIN, я хочу загружать.

2 - Добавить столбец IDENTITY в Score, и это может быть PK.

Можете ли вы, ребята, придумать другое решение?

1 Ответ

1 голос
/ 13 января 2011

Я нашел решение.Я не на 100% доволен этим, но это удовлетворяет моему требованию отсутствия двух таблиц.

На стороне базы данных:

LocationScore:

  • LocationScoreId: IDENTITY, PK
  • LocationId: FK
  • Уникальный индекс LocationId / IsSingleLevelScore

Я импортировал его в свой EDMX - и включилLocationId FK (я обычно никогда не делаю это - но это требуется в этом случае).

Создание производных объектов, сопоставление полей, установка дискриминатора.

Создание связи между Location -> LocationOiversalScore, Location -> LocationScore (на основе ссылочного ограничения LocationId).

Все работает отлично.

Единственный недостаток заключается в том, что поскольку LocationId не является частью PK в таблице LocationScore, он равен 1 .. * между Location и LocationOiversalScore, когда на самом делеэто должен быть только 1..1.

. Я применяю это бизнес-требование в модели через свойство ловушки:

public class Location
{
   // EF navigational properties - required
   public ICollection<LocationOverallScore> LocationOverallScores { get; set; }
   public ICollection<LocationSingleLevelScore> LocationSingleLevelScores { get; set; }

   // Hook properties
   public LocationOverallScore OverallScore
   {
      get { return LocationOverallScores.SingleOrDefault(); }
   }
   public LocationSingleLevelScores SingleLevelScore
   {
      get { return LocationSingleLevelScores .SingleOrDefault(); }
   }
}

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

Так что теперь я могу сделать это:

var location = ctx.Locations.Include("LocationOverallScores").Single();
var overallScore = location.OverallScore;

Это то, с чем я сейчас буду работать.

...