Entity Framework ve SQL Server Görünümü


132

Hakkında konuşma özgürlüğüm olmayan birkaç nedenden ötürü, Sql Server 2005 veritabanımızda şu şekilde bir görüş tanımlıyoruz:

CREATE VIEW [dbo].[MeterProvingStatisticsPoint]
AS
SELECT
    CAST(0 AS BIGINT) AS 'RowNumber',
    CAST(0 AS BIGINT) AS 'ProverTicketId',
    CAST(0 AS INT) AS 'ReportNumber',
    GETDATE() AS 'CompletedDateTime',
    CAST(1.1 AS float) AS 'MeterFactor',
    CAST(1.1 AS float) AS 'Density',
    CAST(1.1 AS float) AS 'FlowRate',
    CAST(1.1 AS float) AS 'Average',
    CAST(1.1 AS float) AS 'StandardDeviation',
    CAST(1.1 AS float) AS 'MeanPlus2XStandardDeviation',
    CAST(1.1 AS float) AS 'MeanMinus2XStandardDeviation'
WHERE 0 = 1

Buradaki fikir, Entity Framework'ün yaptığı bu sorguyu temel alan bir varlık oluşturacağı, ancak aşağıdakileri belirten bir hatayla onu oluşturacağıdır:

Uyarı 6002: Tablo / görünüm 'Keystone_Local.dbo.MeterProvingStatisticsPoint' tanımlı bir birincil anahtara sahip değil. Anahtar çıkarıldı ve tanım salt okunur bir tablo / görünüm olarak oluşturuldu.

Ve CompletedDateTime alanının bu varlık birincil anahtarı olacağına karar verir.

Modeli oluşturmak için EdmGen kullanıyoruz. Varlık çerçevesinin bu görünümün herhangi bir alanını birincil anahtar olarak içermemesinin bir yolu var mı?

Yanıtlar:


245

Aynı sorunu yaşadık ve çözüm bu:

Varlık çerçevesini birincil anahtar olarak bir sütunu kullanmaya zorlamak için ISNULL kullanın.

Varlık çerçevesini bir sütunu birincil anahtar olarak kullanmamaya zorlamak için NULLIF kullanın.

Bunu uygulamanın kolay bir yolu, görünümünüzün seçme ifadesini başka bir seçime kaydırmaktır.

Misal:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp

2
Bence bu umulacak en iyisi. Alt satırda işe yarıyor.
MvcCmsJon

1
Teşekkür ederim! Mükemmel çalıştı. @sabanito Sanırım tanımı ayrıştırıyor. bu nedenle anahtar özellikleri özellikle IsNull () içinde sarmalamanız gerekir. Herhangi bir null döndürmeyen (ve herhangi bir boş değeri döndüremeyen) bir görünüme sahibim, ancak mantığın yazılma şekli nedeniyle EF, anahtarları IsNull () 'a sarana kadar durumun böyle olduğunu belirleyemedi.
Haham

3
Burada gördüğüm tek sorun, görünümün yasal olarak boş bir dize döndürmesi gerekebileceğidir ''. Yaptığım şey, basitçe sütunu kendi veri türüne geri döndürmekti. örneğin, AnotherProperty'nin veri türü varchar (50) olsaydı, bunu 'CONVERT (VARCHAR (50), AnotherProperty) AS [AnotherProperty]' olarak çevirirdim. bu, EF'deki boş değer atanabilirliği maskeledi ve boş dizelere de izin verdi.
Bart

2
evet bu, örneğin EF'nin sütunu birincil anahtar olarak kullanmasını sağlamak için işe yarar (CONVERT (VARCHAR (50), newid ()), '') AS [PK]
dc2009

2
Çözümde sadece can sıkıcı bir mesaj olmasının yanı sıra, bunu düzeltmemenin herhangi bir zararı var mı? Çözümünüze katılıyorum, ama açıkçası bunu yapmam gerektiğini düşünmüyorum - sanırım hepimiz bunun bir hata olduğu konusunda hemfikir olabiliriz, değil mi?
dyslexicanaboko

67

Bunu tasarımcıyı kullanarak çözebildim.

  1. Model Tarayıcıyı açın.
  2. Şemada görünümü bulun.
  3. Birincil anahtara sağ tıklayın ve "Varlık Anahtarı" nın işaretli olduğundan emin olun.
  4. Birincil olmayan tüm anahtarları çoklu seçin. Ctrl veya Shift tuşlarını kullanın.
  5. Özellikler penceresinde (gerekirse F4'e basın), "Varlık Anahtarı" açılır menüsünü Yanlış olarak değiştirin.
  6. Değişiklikleri Kaydet.
  7. Visual Studio'yu kapatın ve yeniden açın. EF 6 ile Visual Studio 2013 kullanıyorum ve uyarıların ortadan kalkması için bunu yapmak zorunda kaldım.

ISNULL, NULLIF veya COALESCE geçici çözümlerini kullanmak için görüşümü değiştirmem gerekmedi. Modelinizi veritabanından güncellerseniz, uyarılar yeniden görünecek, ancak VS'yi kapatıp yeniden açtığınızda kaybolacaktır. Tasarımcıda yaptığınız değişiklikler korunacak ve yenilemeden etkilenmeyecektir.


9
Onaylanmış. Uyarının ortadan kalkması için VS2013'ü yeniden başlatmanız gerekir.
Michael Logutov

5
"Kapatıp tekrar açmayı denediniz mi?" ;-) Teşekkürler, bir cazibe gibi çalışıyor!
Obl Tobl

4
Görünümler oluşturduğumda, model diyagramında bile yer alamıyorlar. Xml dosyasında yorumlanıyorlar
ggderas

Basit ve kolay bir çözüm ve görünümü manipüle etmek kadar hile olmayan bir düzeltme gibi görünmüyor! Teşekkür ederim.
LuqJensen

2
Onaylanan VS2017'nin uyarının da ortadan kalkması için yeniden başlatılması gerekir.
Marc Levesque

46

@Tillito ile anlaşın, ancak çoğu durumda SQL optimizer'ı bozar ve doğru dizinleri kullanmaz.

Birileri için açık olabilir, ancak Tillito çözümünü kullanarak performans sorunlarını çözmek için saatler harcadım. Diyelim ki masanız var:

 Create table OrderDetail
    (  
       Id int primary key,
       CustomerId int references Customer(Id),
       Amount decimal default(0)
    );
 Create index ix_customer on OrderDetail(CustomerId);

ve senin görüşün böyle bir şey

 Create view CustomerView
    As
      Select 
          IsNull(CustomerId, -1) as CustomerId, -- forcing EF to use it as key
          Sum(Amount) as Amount
      From OrderDetail
      Group by CustomerId

Sql iyileştirici ix_customer dizinini kullanmaz ve birincil dizinde tablo taraması gerçekleştirir, ancak bunun yerine:

Group by CustomerId

kullan

Group by IsNull(CustomerId, -1)

MS SQL'in (en az 2008) doğru dizini plana dahil etmesini sağlayacaktır.

Eğer


2
Bu, OP'nin sorusuna bir çözüm sağlamadığı için Tillito'nun cevabına ilişkin bir yorum olmalıdır, bir yanıtın kendisi değil.
zimdanen

6
Adamın 1 temsilcisi var, henüz yorum ekleyemez.
jrcs3

@zimdanen Tüm bu bilgileri bir yoruma sığdırmanın bir yolu yok, ayrı bir cevapta olması daha mantıklı.
Contango

2
@Contango: Bu cevap, gönderildikten altı gün sonra düzenlendi ve ben de yorumumu yayınladım. Düzeltme geçmişine bakın.
zimdanen

9

Bu yöntem benim için iyi çalışıyor. Birincil anahtar alanı için ISNULL () ve alanın birincil anahtar olmaması, ancak aynı zamanda null yapılamayan bir değere sahip olması gerekiyorsa COALESCE () kullanıyorum. Bu örnek, boş değer atanamayan birincil anahtara sahip kimlik alanı verir. Diğer alanlar anahtar değildir ve Null yapılabilir özniteliği olarak (Hiçbiri) vardır.

SELECT      
ISNULL(P.ID, - 1) AS ID,  
COALESCE (P.PurchaseAgent, U.[User Nickname]) AS PurchaseAgent,  
COALESCE (P.PurchaseAuthority, 0) AS PurchaseAuthority,  
COALESCE (P.AgencyCode, '') AS AgencyCode,  
COALESCE (P.UserID, U.ID) AS UserID,  
COALESCE (P.AssignPOs, 'false') AS AssignPOs,  
COALESCE (P.AuthString, '') AS AuthString,  
COALESCE (P.AssignVendors, 'false') AS AssignVendors 
FROM Users AS U  
INNER JOIN Users AS AU ON U.Login = AU.UserName  
LEFT OUTER JOIN PurchaseAgents AS P ON U.ID = P.UserID

Eğer gerçekten bir birincil anahtarınız yoksa, kodunuz tarafından göz ardı edilen bir sözde anahtar oluşturmak için ROW_NUMBER kullanarak bir tane aldatabilirsiniz. Örneğin:

SELECT
ROW_NUMBER() OVER(ORDER BY A,B) AS Id,
A, B
FROM SOMETABLE

Evet, aldatmaya son verdim NEWID() as idama aynı fikir. Ve meşru kullanım durumları vardır - örneğin salt okunur bir görünümünüz varsa. Çirkin, EF, çirkin.
2016

4

Geçerli Entity Framework EDM oluşturucusu, görünümünüzdeki tüm null yapılamayan alanlardan bir bileşik anahtar oluşturacaktır. Bunun üzerinde kontrol elde etmek için, birincil anahtarın parçası olmalarını istemediğinizde sütunları null yapılabilir olarak ayarlayan görünümü ve temel alınan tablo sütunlarını değiştirmeniz gerekecektir. Bunun tersi de doğrudur, karşılaştığım gibi, EDM tarafından oluşturulan anahtar veri çoğaltma sorunlarına neden oluyordu, bu nedenle, EDM'deki bileşik anahtarı bu sütunu dahil etmeye zorlamak için boş değer atanabilir bir sütunu null yapılamaz olarak tanımlamam gerekiyordu.


Çıkarılan PK ile aynı sorunu yaşıyoruz, varlık yinelenen kayıtları döndürüyor ve tamamen can sıkıcı. Yürütürseniz Context.Entity.ToList()doğrudan (LINQPad ile elde) EF tarafından oluşturulan SQL sorgusu çalıştırmak eğer çiftleri kayıtları, ancak, hiçbir kayıt çoğaltılması olur. PK, açıklanan mantık (null yapılamayan sütunlar) kullanılarak elde edildiğinden, veritabanı kayıtlarını döndürülen varlık nesnelerine (POCO) eşlemede bir sorun gibi görünüyor.
David Oliván Ubieto

3

Mantıklı. Öyleyse, onu tanımladığımız şekilde bir sütunu null veya null olarak tanımlamanın bir yolu var mı?
Sergio Romero

1
Maalesef Entity Framework'teki uzmanlık seviyemin çok üzerindeyim. :-)
RBarryYoung

1
Bu sorunun ne zaman çözüleceğini bilen var mı? Birincil anahtar olmayan boş olmayan sütunlarınız olduğunda bu sorunu çözmek zorunda kalmak sinir bozucu.
live-love

3

Bir görünüm elde etmek için sadece göstermek zorunda tane birincil anahtar sütununu birinciye işaret eden ikinci bir görünüm oluşturdum ve türleri null yapılabilir hale getirmek için NULLIF kullandım. Bu, EF'i görünümde yalnızca tek bir birincil anahtar olduğunu düşündürmek için çalıştı.

EF'nin NO birincil anahtarı olmayan bir varlığı kabul edeceğine inanmadığım için bunun size yardımcı olup olmayacağından emin değilim.


3

Birincil anahtarın ne olması gerektiği ile uğraşmak istemiyorsanız, şunları tavsiye ederim:

  1. Birleştirmek ROW_NUMBER Seçiminiz içine
  2. Birincil anahtar olarak ayarlayın
  3. Modeldeki diğer tüm sütunları / üyeleri birincil olmayan olarak ayarla

1

Yukarıda bahsedilen problemlerden dolayı tablo değeri fonksiyonlarını tercih ediyorum.

Eğer buna sahipseniz:

CREATE VIEW [dbo].[MyView] AS SELECT A, B FROM dbo.Something

bunu oluştur:

CREATE FUNCTION MyFunction() RETURNS TABLE AS RETURN (SELECT * FROM [dbo].[MyView])

Ardından, görünüm yerine işlevi içe aktarırsınız.


2
Bu yaklaşımla varlıklar arasında nasıl ilişki kurarsınız? Mümkün mü?
ggderas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.