2016-02-23 4 views
6

У меня есть Linq к SQL следующим образом:Linq к Sql графу Включает присоединяется

var members=db.Members.Include(x=> x.Contact).Count(); 

Теперь из-за некоторые плохие данные всех контактов в членах моих нет соответствующего контакт записи. Итак, во время подсчета, как я могу включить граф после Inner Join в таблицу контактов.

Проблема заключается в том, когда я получить список членов, список членов имеет 100 записей, в то время как граф имеет 150 записей (50 записей Неуспехи данных).

var membersQ=db.Members.Include(x=> x.Contact).Select(i=> new MemberViewModel(){ 
Name = i.Contact.Name, 
ContactId= i.Contact.Id, 
CreatedDate= i.CreatedDate 
}).AsQueryable(); 
var members=memberQ.ToList();// =100,paging is done... 
// the memebers list uses paging but the count doesn't 
var total=membersQ.Count(); // =150 

Я проверил Результирующий запрос во время подсчета голосов, по-видимому, он не делает JOIN с контактным столом, а Count()

Update структура базы данных

Member Table 
Id ContactId, CompanyId, CreatedDate ... 

Contact Table 
Id Name ... 

Внешний ключ, для ContactId в Таблица участников не задана на уровне базы данных, а только на модели.

[ForeignKey("ContactId")] 
Public Contact Contact { get; set; } 

Плохие данные поступают как этот

я был ранее 1,2,3,4,5,6,7,8,9,10 в качестве контактных записей и все эти контакты были в таблице членами слишком.

Теперь я удалил записи из таблицы контактов, скажем, 6-10. Но не удалялось из таблицы Member.

Так что это вызывает проблему со счетом. Я уверен, что удаление плохих данных от Member решает проблему, но вопрос в том, как использовать join while using Count().

Примечание: Я использую инициализатор базы данных нулевой

Update 2 Я LINQPad и пытался как по умолчанию Linq To SQL и EntityFramework соединение (DbContext) и то, что я нашел это сбивает с толку.

Для запроса:

(from a in Members 
join b in Contacts on a.ContactId equals b.ContactId 
select a).Count() 

Использование по умолчанию Linq To SQL

SELECT COUNT(*) AS [value] 
FROM [Member] AS [t0] 
INNER JOIN [Contact] AS [t1] ON [t0].[ContactID] = [t1].[ContactID] 

Использование Entityframework DbContext

SELECT 
    [GroupBy1].[A1] AS [C1] 
    FROM (SELECT 
     COUNT(1) AS [A1] 
     FROM [dbo].[Member] AS [Extent1] 
    ) AS [GroupBy1] 

В моем коде я использую метод DbContext. Итак ... не знаю, что делать здесь . кстати: Извините за то, что тег с linq-to-sql это на самом деле entityframework

+0

просто для удовольствия. пытаться. memberQ.Contacts.Count() (это должно быть 100) –

+0

Так что мне придется использовать другой запрос, который выбирает 'Contact', чем тот, который используется для' ToList'? – Ruchan

ответ

4

Что об этом:

var x = from m in Members 
     join c in Contacts on m.ContactId equals c.ID 
     select new 
     { 
      Name = c.Name, 
      ContactId= c.ID, 
      CreatedDate= c.CreatedDate 
     }; 

Console.Write(x.Count()); 

EDIT

Когда я использую LINQPad с этим запросом и смотреть на сгенерированного SQL я получаю:

SELECT COUNT(*) AS [value] 
FROM [Members] AS [t0] 
INNER JOIN [Contact] AS [t1] ON [t0].[ContactId] = ([t1].[ID]) 

EDIT 2

Вы также можете попробовать это:

var x = from c in Contacts 
     from m in Members where m.ContactId == c.ID 
     select new 
     { 
      Name = c.Name, 
      ContactId= c.ID, 
      CreatedDate= c.CreatedDate 
     }; 

Console.Write(x.Count()); 
+0

На самом деле это также не работает, итоговый запрос не работает с 'Contact' – Ruchan

+0

@Ruchan, когда я использую LinqPAd и запускаю запрос. Я получаю Inner Join: SELECT COUNT (*) AS [значение] FROM [Members ] AS [t0] INNER JOIN [Контакт] AS [t1] ON [t0]. [ContactId] = ([t1]. [ID]) –

+0

см. Обновленный пост – Ruchan

2

Не уверен, если это правильно, но, являются записи, содержащие неверные данные, дубликаты? Если да, то почему бы не использовать отдельные(), чтобы получить только 100 хороших записей?Если все, что вы хотите, это просто счетчик из списка, то почему бы не использовать:

var members = memberQ.ToList(); 
int total = members.Count; 
+0

Для примера я использовал ToList напрямую, но мне нужно сделать подкачку в записях. У счетчика не требуется пейджинг. – Ruchan

2

Ответ на этот просто не имеют никакой связи между членами и Контакта. Таблица членов имеет 150 строк, а таблица контактов - 100 строк. Поэтому, когда вы пытаетесь получить, вы фактически соединяете данные по строкам, пока не закончится какая-либо таблица. Когда вы считаете, что считаете первую таблицу.

Решение Вам необходимо добавить FK для контактов от членов или к любому типу идентификатора, который вы можете «привязать» данные к Участникам от контакта.

Более объяснение & еще в комментариях

В таблице Members у вас есть ссылка на Contact. которые вы заселить с Include(x=> x.Contact) заявление

Так что, когда вы пытаетесь сделать это

new MemberViewModel(){ 
    Name = i.Contact.Name, 
    ContactId= i.Contact.Id, 
    CreatedDate= i.CreatedDate 
} 

Вы просите содержание Контакта (как вы, наверное, знаете.)

Теперь для некоторого объяснения. Когда вы запрашиваете базу данных, как вы делаете в MembersQ, вы не получаете/не реализуете данные. (Вы только готовит запрос)

Для реализации запроса необходимо позвонить ToArray(), ToList() и т.д. И когда вы делаете foreach на данных, реализовать одну строку за один раз (курсор).

Теперь для вашего результата, когда вы звоните ToList() вы осознав список List типа (теперь только элементы, способные заполнить используются (это ваш 100))

Когда вы выполняете memberQ.Count() вы спрашиваете для подсчета запроса из базы данных, поскольку база данных ничего не знает о MemberViewModel будет возвращать отсчеты членов соответствующих возможные Where(x=>{filter}) (это ваши 150)

Простого исправления писать ToList() вместо AsQueryable(). Im alittle ржавый на LINQ-to-SQL, возможно, вам нужно будет AsQueryable().ToList()

Возможное решение для фильтрации заранее.

var membersQ=db.Members.Include(x=> x.Contact).Where(a=> a.Contact != null).Select(i=> new MemberViewModel(){ 
    Name = i.Contact.Name, 
    ContactId= i.Contact.Id, 
    CreatedDate= i.CreatedDate 
}).AsQueryable(); 

Теперь membersQ.Count() должна быть равна вар membersQ.ToList().Count()

и выполнить использование memberQ.Skip(x).Take(y) подкачки это будет выполняться на SQL, а не на веб-сервере. Если вы не ToList(), то все на сервере, как его вдруг набор данных в памяти сервера.

Если это не работает, то у вас нет ключа для переднего края, вы можете просто сменить фильтр для фильтрации в ContactID вместо Contact.of add a FK (Foreign Key)

Добавить внешний ключ: Если у вас есть доступ к модификации вашего SQL, тогда сделайте ContactID в Member nullable и добавьте внешний ключ от членов ContactID и ID контакта.

Затем удалите две таблицы из своего dbml и перетащите их снова из db explorer. Теперь вы должны быть в состоянии просто использовать код без включает в себя, как будет «Ленивый загружен» есть (то есть не включает в себя) по сравнению с Нетерпеливый загружен (то есть вы должны сказать, что для загрузки)

+0

Да, 'ToList' действительно решает проблему, но создает еще одну проблему. ** Слишком много данных ** В «ToList» будут перечислены все записи из базы данных, которые при использовании пейджинга не требуются. Да, я не привел пример пейджинга, но я процитировал в сообщении, что будет пейджинг. Счетчик - это общее количество записей в базе данных без пейджинга. – Ruchan

+0

Добавлен пример внизу, см., Если это не помогает –

+0

Я использовал 'a.Contact! = Null', и он все еще не работает. В результате запроса нет соединения или проверки существующего 'Contact' на' Count() ' – Ruchan

0
var members = db.Contracts.Where(w=> w.Member != null).Select(i=> new MemberViewModel(){ 
Name = i.Contact.Name, 
ContactId= i.Contact.Id, 
CreatedDate= i.CreatedDate 
}).AsQueryable()); 

Это несколько, что вы после этого?

1

попробовать этот

var members=db.Members.Include(x=> x.Contact) 
         .Where(x => x.Contact != null) 
         .Count(); 
Смежные вопросы