Как я могу использовать Entity Framework на графе объектов после глубины 2 с MySQL Connector / NET?

Вот подтвержденное сообщение об ошибке в Oracle:http://bugs.mysql.com/bug.php?id=67183

Situation

При использовании.Include В цепочке внутри моего репозитория я заметил, что получаю странные результаты - в основном, то, что запрашиваемые значения возвращались из неправильных полей (например, имя будет в описании в описании), но в базе данных все значения верны, они только показывать неправильно после запроса). Я изменил имена, чтобы отношения были более очевидными, но структура та же самая. Я продолжаю получать неправильные значения для связанного CrewMember и их относительного ранга и разрешения. Кажется, если есть имя поля, которое совпадает в CrewMember с Rank, тогда значение этого поля в Rank становится тем же, что и в CrewMember. Например, если у Rank есть описание, как и у CrewMember, тогда описание Rank для CrewMember будет описанием CrewMember.

Entity Framework не в состоянии делать правильно сформированные запросы после глубины 2, когда есть подобные поля, определенные в результате MySQL Connector / NET sql провайдера, который не может правильно сформироватьjoin заявления.

Definitions

Это определение класса, которое моделирует таблицу базы данных. Я использую C # ASP.NET MVC 3 с Entity Framework 4.1 и MySQL Connector / NET версии 6.5

public class Harbor
{
 public int HarborId { get; set; }
 public virtual ICollection<Ship> Ships { get; set; }
 public string Description { get; set; }
}

public class Ship
{
 public int ShipId { get; set; }
 public int HarborId { get; set; }
 public virtual Harbor Harbor { get; set; }
 public virtual ICollection<CrewMember> CrewMembers { get; set; }
 public string Description { get; set; }
} 

public class CrewMember
{
 public int CrewMemberId { get; set; }
 public int ShipId { get; set; }
 public virtual Ship Ship { get; set; }
 public int RankId { get; set; }
 public virtual Rank Rank { get; set; }
 public int ClearanceId { get; set; }
 public virtual Clearance Clearance { get; set; }
 public string Description { get; set; }
}

public class Rank
{
 public int RankId { get; set; }
 public virtual ICollection<CrewMember> CrewMembers { get; set; }
 public string Description { get; set; }
}

public class Clearance
{
 public int ClearanceId { get; set; }
 public virtual ICollection<CrewMember> CrewMembers { get; set; }
 public string Description { get; set; }
}

Query

Это код, который запрашивает базу данных и имеет запросы и вызовы .Include.

DbSet<Harbor> dbSet = context.Set<Harbor>();
IQueryable<Harbor> query = dbSet;
query = query.Include(entity => entity.Ships);
query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers));
query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers.Select(cm => cm.Rank)));
query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers.Select(cm => cm.Clearance)));

Эти.Include звонки правильно сформированы? Я что-то пропустил?

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

How can I use Entity Framework to get a well formed query on an object graph past a depth of 2 when using MySQL Connector / NET?

Edits

Вот сгенерированный запрос:

{SELECT
[Project1].[HarborId], 
[Project1].[Description], 
[Project1].[C2] AS [C1], 
[Project1].[ShipId], 
[Project1].[HarborId1], 
[Project1].[Description1], 
[Project1].[C1] AS [C2], 
[Project1].[CrewMemberId], 
[Project1].[ShipId1], 
[Project1].[ClearanceId], 
[Project1].[RankId], 
[Project1].[Description2], 
[Project1].[RankId1], 
[Project1].[Description3], 
[Project1].[ClearanceId1], 
[Project1].[Description4], 
FROM (SELECT
[Extent1].[HarborId], 
[Extent1].[Description], 
[Join3].[ShipId], 
[Join3].[HarborId] AS [HarborId1], 
[Join3].[Description]AS [Description1], 
[Join3].[CrewMemberId], 
[Join3].[ShipId]AS [ShipId1], 
[Join3].[ClearanceId], 
[Join3].[RankId], 
[Join3].[Description] AS [Description2], 
[Join3].[RankId] AS [RankId1], 
[Join3].[Description] AS [Description3], 
[Join3].[ClearanceId] AS [ClearanceId1], 
[Join3].[Description] AS [Description4], 
CASE WHEN ([Join3].[ShipId] IS  NULL) THEN (NULL)  WHEN ([Join3].[CrewMemberId] IS  NULL) THEN (NULL)  ELSE (1) END AS [C1], 
CASE WHEN ([Join3].[ShipId] IS  NULL) THEN (NULL)  ELSE (1) END AS [C2]
FROM [Harbor] AS [Extent1] LEFT OUTER JOIN (SELECT
[Extent2].[ShipId], 
[Extent2].[HarborId], 
[Extent2].[Description], 
[Join2].[CrewMemberId], 
[Join2].[ShipId] AS [ShipID1], 
[Join2].[ClearanceId], 
[Join2].[RankId], 
[Join2].[Description] AS [DESCRIPTION1], 
[Join2].[RankID1], 
[Join2].[DESCRIPTION1] AS [DESCRIPTION11], 
[Join2].[ClearanceID1], 
[Join2].[DESCRIPTION2], 
FROM [Ship] AS [Extent2] LEFT OUTER JOIN (SELECT
[Extent3].[CrewMemberId], 
[Extent3].[ShipId], 
[Extent3].[ClearanceId], 
[Extent3].[RankId], 
[Extent3].[Description], 
[Extent4].[RankId] AS [RankID1], 
[Extent4].[Description] AS [DESCRIPTION1], 
[Extent5].[ClearanceId] AS [ClearanceID1], 
[Extent5].[Description] AS [DESCRIPTION2], 
FROM [CrewMember] AS [Extent3] INNER JOIN [Rank] AS [Extent4] ON [Extent3].[RankId] = [Extent4].[RankId] LEFT OUTER JOIN [Clearance] AS [Extent5] ON [Extent3].[ClearanceId] = [Extent5].[ClearanceId]) AS [Join2] ON [Extent2].[ShipId] = [Join2].[ShipId]) AS [Join3] ON [Extent1].[HarborId] = [Join3].[HarborId]
 WHERE [Extent1].[HarborId] = @p__linq__0) AS [Project1]
 ORDER BY 
[Project1].[HarborId] ASC, 
[Project1].[C2] ASC, 
[Project1].[ShipId] ASC, 
[Project1].[C1] ASC}

Clarification

Использование отношений «включить на 1-1» не создает проблем при «сверлении». таким образом, кажется. Тем не менее, проблема, кажется, возникает, когда есть 1-много отношений как часть бурения. Бурение необходимо для того, чтобы увеличить нагрузку.

Первая проекция,entity => entity.Ships.Select(s => s.CrewMembers, вернет список членов экипажа, связанных с каждым кораблем. Это правильно возвращает график, где гавань содержит список кораблей, каждый со списком членов экипажа.

Тем не менее, второй прогнозCrewMembers.Select(cm => cm.Rank, фактически не возвращает правильную часть графа. Поля начинают смешиваться, и любые поля, имеющие одно и то же имя, по умолчанию по умолчанию будут родительским полем. Это приводит к противоречивым результатам и, что более важно, к неверным данным. Тот факт, что никаких ошибок не возникает, усугубляет ситуацию, поскольку это можно определить только путем проверки во время выполнения.

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

Если вместо CrewMembers, являющегося ICollection, это был только один CrewMember, то эта вложенная проекция фактически вернет правильные данные. Тем не менее, это упрощенная версия этой проблемы, и, к сожалению, это то, что почти все тестирование, по-видимому, было сделано из различных блогов, учебных пособий, сообщений, статей и документов, которые я рассмотрел, пытаясь решить эту проблему.

Ответы на вопрос(3)

Ваш ответ на вопрос