Khung thực thể và SQL Server View


132

Vì nhiều lý do mà tôi không có quyền tự do để nói, chúng tôi đang xác định chế độ xem trên cơ sở dữ liệu Sql Server 2005 của chúng tôi như vậy:

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

Ý tưởng là Entity Framework sẽ tạo ra một thực thể dựa trên truy vấn này, nhưng nó tạo ra nó với một lỗi có nội dung như sau:

Cảnh báo 6002: Bảng / chế độ xem 'Keystone_Local.dbo.MeterProvingStatisticPoint' không có khóa chính được xác định. Khóa đã được suy ra và định nghĩa được tạo dưới dạng bảng / khung nhìn chỉ đọc.

Và nó quyết định rằng trường CompleteedDateTime sẽ là khóa chính thực thể này.

Chúng tôi đang sử dụng EdmGen để tạo mô hình. Có cách nào để không có khung thực thể bao gồm bất kỳ trường nào của chế độ xem này làm khóa chính không?

Câu trả lời:


245

Chúng tôi đã có cùng một vấn đề và đây là giải pháp:

Để buộc khung thực thể sử dụng cột làm khóa chính, hãy sử dụng ISNULL.

Để buộc khung thực thể không sử dụng cột làm khóa chính, hãy sử dụng NULLIF.

Một cách dễ dàng để áp dụng điều này là bọc câu lệnh chọn của chế độ xem của bạn trong vùng chọn khác.

Thí dụ:

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

2
Tôi nghĩ rằng đây là điều tốt nhất để được hy vọng. Dòng dưới cùng nó hoạt động.
MvcCmsJon

1
Cảm ơn bạn! Nó hoạt động hoàn hảo. @sabanito Tôi nghĩ nó phân tích định nghĩa. đó là lý do tại sao bạn cần bọc cụ thể các thuộc tính chính trong IsNull (). Tôi có một quan điểm không trả về bất kỳ giá trị null nào (và không thể trả lại bất kỳ giá trị null nào) nhưng do cách viết logic, EF không thể xác định đó là trường hợp cho đến khi tôi bọc các khóa trong IsNull ().
Rabbi

3
Vấn đề duy nhất tôi thấy ở đây là quan điểm đó có thể cần phải trả lại một chuỗi trống ''. Những gì tôi đã làm, chỉ đơn giản là đưa cột trở lại kiểu dữ liệu của chính nó. ví dụ: nếu AnotherProperty có kiểu dữ liệu varchar (50), tôi sẽ sử dụng nó như 'CONVERT (VARCHAR (50), AnotherProperty) AS [AnotherProperty]'. điều này che dấu sự vô hiệu từ EF và cũng cho phép các chuỗi trống.
Bart

2
vâng, điều này hoạt động chẳng hạn để làm cho EF sử dụng cột làm khóa chính (CONVERT (VARCHAR (50), newid ()), '') NHƯ [PK]
dc2009

2
Bên cạnh đó chỉ là một thông điệp gây phiền nhiễu trong giải pháp, có bất kỳ tác hại nào trong việc không khắc phục điều này? Tôi đồng ý với giải pháp của bạn, nhưng thật lòng tôi không cảm thấy rằng tôi nên làm điều này - tôi nghĩ tất cả chúng ta có thể đồng ý đây là một lỗi phải không?
chứng khó đọc

67

Tôi đã có thể giải quyết điều này bằng cách sử dụng các nhà thiết kế.

  1. Mở Trình duyệt mô hình.
  2. Tìm khung nhìn trong sơ đồ.
  3. Nhấp chuột phải vào khóa chính và đảm bảo "Khóa thực thể" được chọn.
  4. Đa lựa chọn tất cả các khóa không chính. Sử dụng các phím Ctrl hoặc Shift.
  5. Trong cửa sổ Thuộc tính (nhấn F4 nếu cần để xem), thay đổi thả xuống "Khóa thực thể" thành Sai.
  6. Lưu thay đổi.
  7. Đóng Visual Studio và mở lại. Tôi đang sử dụng Visual Studio 2013 với EF 6 và tôi đã phải làm điều này để cảnh báo biến mất.

Tôi không phải thay đổi quan điểm của mình để sử dụng các cách giải quyết ISNULL, NULLIF hoặc COALESCE. Nếu bạn cập nhật mô hình của mình từ cơ sở dữ liệu, các cảnh báo sẽ xuất hiện lại, nhưng sẽ biến mất nếu bạn đóng và mở lại VS. Những thay đổi bạn thực hiện trong nhà thiết kế sẽ được bảo tồn và không bị ảnh hưởng bởi việc làm mới.


9
Đã xác nhận. Phải khởi động lại VS2013 để cảnh báo biến mất.
Michael Logutov

5
"Bạn đã thử tắt nó đi và bật lại chưa?" ;-) Cảm ơn, làm việc như một cơ duyên!
Obl Tobl

4
Khi tôi tạo chế độ xem, chúng thậm chí không được đưa vào sơ đồ mô hình. Họ đã nhận xét trong tệp xml
ggderas

Giải pháp đơn giản và dễ dàng và dường như không có nhiều sửa chữa không hack như thao túng chế độ xem! Cảm ơn bạn.
LuqJensen

2
Xác nhận VS2017 cũng cần phải được khởi động lại để cảnh báo biến mất.
Marc Levesque

46

Đồng ý với @Tillito, tuy nhiên trong hầu hết các trường hợp, nó sẽ phạm lỗi với trình tối ưu hóa SQL và nó sẽ không sử dụng các chỉ mục đúng.

Nó có thể rõ ràng đối với ai đó, nhưng tôi đã đốt cháy hàng giờ để giải quyết các vấn đề về hiệu suất bằng giải pháp Tillito. Hãy nói rằng bạn có bảng:

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

và quan điểm của bạn là một cái gì đó như thế này

 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

Trình tối ưu hóa Sql sẽ không sử dụng chỉ mục ix_customer và nó sẽ thực hiện quét bảng trên chỉ mục chính, nhưng nếu thay vì:

Group by CustomerId

bạn sử dụng

Group by IsNull(CustomerId, -1)

nó sẽ làm cho MS SQL (ít nhất là 2008) bao gồm chỉ mục đúng vào kế hoạch.

Nếu


2
Đây phải là một nhận xét về câu trả lời của Tillito, chứ không phải là một câu trả lời, vì nó không cung cấp giải pháp cho câu hỏi của OP.
zimdanen

6
Anh chàng có số điểm là 1, anh ta chưa thể thêm bình luận.
jrcs3

@zimdanen Không có cách nào bạn có thể đưa tất cả thông tin này vào một bình luận, sẽ có ý nghĩa hơn khi có nó trong một câu trả lời riêng biệt.
Contango

2
@Contango: Câu trả lời này đã được chỉnh sửa sáu ngày sau khi được đăng và tôi đã đăng bình luận của mình. Xem lịch sử sửa đổi.
zimdanen

9

Phương pháp này hoạt động tốt cho tôi. Tôi sử dụng ISNULL () cho trường khóa chính và COALESCE () nếu trường không phải là khóa chính, nhưng cũng nên có giá trị không thể rỗng. Ví dụ này mang lại trường ID với khóa chính không thể rỗng. Các trường khác không phải là khóa và có (Không) là thuộc tính Nullable của chúng.

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

nếu bạn thực sự không có khóa chính, bạn có thể giả mạo bằng cách sử dụng ROW_NUMBER để tạo khóa giả bị bỏ qua bởi mã của bạn. Ví dụ:

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

Vâng, cuối cùng tôi đã gian lận NEWID() as id, nhưng đó là cùng một ý tưởng. Và có những trường hợp sử dụng hợp pháp - ví dụ: nếu bạn có chế độ xem chỉ đọc. Xấu xí, EF, xấu xí.
ruffin

4

Trình tạo EDM Entity hiện tại sẽ tạo một khóa tổng hợp từ tất cả các trường không thể rỗng trong chế độ xem của bạn. Để giành quyền kiểm soát điều này, bạn sẽ cần sửa đổi chế độ xem và các cột trong bảng đặt các cột thành nullable khi bạn không muốn chúng là một phần của khóa chính. Điều ngược lại cũng đúng, như tôi gặp phải, khóa tạo EDM đã gây ra sự cố trùng lặp dữ liệu, vì vậy tôi phải xác định một cột không thể là không thể để buộc khóa tổng hợp trong EDM phải bao gồm cột đó.


Chúng tôi có cùng một vấn đề với PK được suy luận, thực thể trả về các bản ghi trùng lặp và hoàn toàn khó chịu. Nếu bạn thực hiện các Context.Entity.ToList()bản ghi trùng lặp, nhưng nếu bạn thực hiện Truy vấn SQL được tạo trực tiếp bởi EF (thu được bằng LINQPad), sẽ không xảy ra sự trùng lặp bản ghi. Có vẻ như là một vấn đề ánh xạ các bản ghi cơ sở dữ liệu đến các đối tượng thực thể (POCO) được trả về, vì PK được suy ra bằng cách sử dụng logic được giải thích (các cột không thể rỗng).
David Oliván Ubieto

3

Điều đó có ý nghĩa. Vì vậy, có cách nào để xác định một cột là không null hoặc null trong một khung nhìn theo cách chúng ta đang xác định nó?
Sergio Romero

1
Xin lỗi, tôi đã vượt quá trình độ chuyên môn của mình trong Entity Framework. :-)
RBarryYoung

1
Có ai biết khi nào vấn đề này sẽ được khắc phục? Khó chịu khi phải giải quyết vấn đề này khi bạn có các cột không null không phải là khóa chính.
sống tình yêu

3

Để có được một cái nhìn tôi phải chỉ hiển thị một cột khóa chính, tôi đã tạo một khung nhìn thứ hai chỉ vào NULLIF đầu tiên và được sử dụng để làm cho các kiểu không thể thực hiện được. Điều này làm việc cho tôi để làm cho EF nghĩ rằng chỉ có một khóa chính duy nhất trong chế độ xem.

Không chắc chắn nếu điều này sẽ giúp bạn mặc dù tôi không tin rằng EF sẽ chấp nhận một thực thể không có khóa chính.


3

Nếu bạn không muốn gây rối với những gì nên là khóa chính, tôi khuyên bạn nên:

  1. Kết hợp ROW_NUMBER vào lựa chọn của bạn
  2. Đặt nó làm khóa chính
  3. Đặt tất cả các cột / thành viên khác là không chính trong mô hình

1

Do các vấn đề đã đề cập ở trên, tôi thích các hàm giá trị bảng.

Nếu bạn có điều này:

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

tạo cái này

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

Sau đó, bạn chỉ cần nhập chức năng chứ không phải xem.


2
Làm thế nào bạn sẽ tạo ra sự liên kết giữa các thực thể với phương pháp này? Có thể không?
ggderas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.