Я очень плохо знаком с.NET Entity Framework, и я думаю, что это потрясающее, но так или иначе я получаю эту странную проблему (извините для испанцев, но моя программа находится на том языке, так или иначе это не имеет большого значения, просто колонка или имущественные имена): я делаю нормальный LINQ К вопросу Предприятий, чтобы получить список UltimaConsulta, как это:
var query = from uc in bd.UltimasConsultas
select uc;
UltimasConsultas - представление, btw. Вещь состоит в том, что LINQ производит этот SQL для вопроса:
SELECT
[Extent1].[IdPaciente] AS [IdPaciente],
[Extent1].[Nombre] AS [Nombre],
[Extent1].[PrimerApellido] AS [PrimerApellido],
[Extent1].[SegundoApellido] AS [SegundoApellido],
[Extent1].[Fecha] AS [Fecha]
FROM (SELECT
[UltimasConsultas].[IdPaciente] AS [IdPaciente],
[UltimasConsultas].[Nombre] AS [Nombre],
[UltimasConsultas].[PrimerApellido] AS [PrimerApellido],
[UltimasConsultas].[SegundoApellido] AS [SegundoApellido],
[UltimasConsultas].[Fecha] AS [Fecha]
FROM [dbo].[UltimasConsultas] AS [UltimasConsultas]) AS [Extent1]
Почему LINQ производит вложенное Избранное? Я думал от видео и примеров, что это производит нормальный SQL, выбирает для этого вида вопросов. Я должен настроить что-то (модель предприятия производила от волшебника, таким образом, это - конфигурация по умолчанию)? Заранее спасибо за Ваши ответы.
, чтобы быть понятным, Linq к объектам не генерируют SQL. Вместо этого он генерирует каноническое дерево ADO.Net, а поставщик Ado.net для вашей базы данных, предположительно SQL Server в этом случае, генерирует SQL.
Итак, почему он генерирует эту полученную таблицу (я думаю, что «полученная таблица» - это более правильный срок для функции SQL здесь)? Поскольку код, который генерирует SQL, должен генерировать SQL для широкого спектра запросов LINQ, большинство из которых находятся не так тривиально, как и вы показываете. Эти запросы часто будут выбирать данные для нескольких типов (многие из которых могут быть анонимными, а не названными типами), а также для того, чтобы сохранить сравнительно здание SQL, они сгруппированы в экстенцию для каждого типа.
Другой вопрос: почему вы должны заботиться? Легко продемонстрировать, что использование производной таблицы в этом утверждении «бесплатно» с точки зрения производительности.
Я выбрал таблицу случайным образом из заполненной базы данных и выполнял следующий запрос:
SELECT [AddressId]
,[Address1]
,[Address2]
,[City]
,[State]
,[ZIP]
,[ZIPExtension]
FROM [VertexRM].[dbo].[Address]
Давайте посмотрим на стоимость:
<StmtSimple StatementCompId="1" StatementEstRows="7900" StatementId="1" StatementOptmLevel="TRIVIAL" StatementSubTreeCost="0.123824" StatementText="/****** Script for SelectTopNRows command from SSMS ******/
SELECT [AddressId]
 ,[Address1]
 ,[Address2]
 ,[City]
 ,[State]
 ,[ZIP]
 ,[ZIPExtension]
 FROM [VertexRM].[dbo].[Address]" StatementType="SELECT">
<StatementSetOptions ANSI_NULLS="false" ANSI_PADDING="false" ANSI_WARNINGS="false" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="false" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="false" />
<QueryPlan CachedPlanSize="9" CompileTime="0" CompileCPU="0" CompileMemory="64">
<RelOp AvgRowSize="246" EstimateCPU="0.008847" EstimateIO="0.114977" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="7900" LogicalOp="Clustered Index Scan" NodeId="0" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.123824">
Теперь давайте сравним это на запрос с полученной таблицей:
SELECT
[Extent1].[AddressId]
,[Extent1].[Address1]
,[Extent1].[Address2]
,[Extent1].[City]
,[Extent1].[State]
,[Extent1].[ZIP]
,[Extent1].[ZIPExtension]
FROM (SELECT [AddressId]
,[Address1]
,[Address2]
,[City]
,[State]
,[ZIP]
,[ZIPExtension]
FROM[VertexRM].[dbo].[Address]) AS [Extent1]
и стоимость :
<StmtSimple StatementCompId="1" StatementEstRows="7900" StatementId="1" StatementOptmLevel="TRIVIAL" StatementSubTreeCost="0.123824" StatementText="/****** Script for SelectTopNRows command from SSMS ******/
SELECT 
 [Extent1].[AddressId]
 ,[Extent1].[Address1]
 ,[Extent1].[Address2]
 ,[Extent1].[City]
 ,[Extent1].[State]
 ,[Extent1].[ZIP]
 ,[Extent1].[ZIPExtension]
 FROM (SELECT [AddressId]
 ,[Address1]
 ,[Address2]
 ,[City]
 ,[State]
 ,[ZIP]
 ,[ZIPExtension]
 FROM[VertexRM].[dbo].[Address]) AS [Extent1]" StatementType="SELECT">
<StatementSetOptions ANSI_NULLS="false" ANSI_PADDING="false" ANSI_WARNINGS="false" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="false" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="false" />
<QueryPlan CachedPlanSize="9" CompileTime="0" CompileCPU="0" CompileMemory="64">
<RelOp AvgRowSize="246" EstimateCPU="0.008847" EstimateIO="0.114977" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="7900" LogicalOp="Clustered Index Scan" NodeId="0" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.123824">
В обоих случаях SQL Server просто сканирует кластерный индекс. Неудивительно, что стоимость почти точно такой же.
Давайте посмотрим на слегка более сложный запрос. Я выпустил LinqPAD и вошел в следующие запросы против одной таблицы, плюс одна связанная таблица:
from a in Addresses
select new
{
Id = a.Id,
Address1 = a.Address1,
Address2 = a.Address2,
City = a.City,
State = a.State,
ZIP = a.ZIP,
ZIPExtension = a.ZIPExtension,
PersonCount = a.EntityAddresses.Count()
}
Это генерирует следующие SQL:
SELECT
1 AS [C1],
[Project1].[AddressId] AS [AddressId],
[Project1].[Address1] AS [Address1],
[Project1].[Address2] AS [Address2],
[Project1].[City] AS [City],
[Project1].[State] AS [State],
[Project1].[ZIP] AS [ZIP],
[Project1].[ZIPExtension] AS [ZIPExtension],
[Project1].[C1] AS [C2]
FROM ( SELECT
[Extent1].[AddressId] AS [AddressId],
[Extent1].[Address1] AS [Address1],
[Extent1].[Address2] AS [Address2],
[Extent1].[City] AS [City],
[Extent1].[State] AS [State],
[Extent1].[ZIP] AS [ZIP],
[Extent1].[ZIPExtension] AS [ZIPExtension],
(SELECT
COUNT(cast(1 as bit)) AS [A1]
FROM [dbo].[EntityAddress] AS [Extent2]
WHERE [Extent1].[AddressId] = [Extent2].[AddressId]) AS [C1]
FROM [dbo].[Address] AS [Extent1]
) AS [Project1]
, анализируя это, мы видим, что Project1
- это Проекция на анонимный тип. Extent1
- это адрес
таблица / объекта. И Extent2
- это таблица для ассоциации. Сейчас нет производного стола для адреса
, но есть один для проекции.
Я не знаю, если вы когда-либо написали систему поколений SQL, но это не легко. Я считаю, что общая проблема доказывает, что запрос LINQ к объектам и запрос SQL эквивалентен, является NP-Hard, хотя определенные конкретные случаи, очевидно, намного проще. SQL намеренно является неполным, потому что его дизайнеры хотели, чтобы все запросы SQL выполняются в ограниченном времени. Linq, не так.
Короче говоря, это очень сложная проблема для решения, а комбинация структуры субъекта и его поставщиков иногда приносят жертвующую доступность в пользу согласованности в течение широкого спектра запросов. Но это не должно быть проблемой производительности.
Монитор и базовый «синхронизм», который может быть связан с любым эталонным объектом - основным механизмом под блокировкой C #
. Только один нить может иметь замок. Это просто и эффективно.
ReaderWriterLock
(или, в V3.5, тем лучше ReaderWriterLockSlim
) обеспечивает более сложную модель. Избегайте, если вы не знаете , это будет более эффективным (то есть есть измерения производительности для поддержки себя).
Лучший вид блокировки - это запирание, вам не нужно (то есть не делитесь данными между потоками).
-121--921034-В основном он определяет, какой Extent1 состоит из и какие переменные будут относиться к каждой записи. Затем его отображение фактической таблицы базы данных в Extent1, чтобы она мог вернуть все записи для этой таблицы.
Это то, что ваш запрос просит. Это просто, что LINQ не может добавить в персонаж подстановки, как вы, если вы сделали его вручную.