我们在数据库中有一个人搜索存储过程,我想在我的edmx
文件中映射到Visual Studio 2012。存储过程返回满足搜索的行,并设置返回码。当我手动执行存储过程时,我得到了我期望的4行,并且返回代码为0.
我在框架中使用2012,EF 5和Entity Framework组件。
当我通过UpdateModelFromDatabase
选择存储过程并将其添加到我的项目时,而不是定义通常的{storedProcedureName}_Result
并返回它,它被转换为仅返回一个整数。这使我无法使用存储过程实际到达行来显示它们。
有趣的是,我们有一个测试PersonSearch
存储过程,它恰好被破坏了,但它是一个内部更改的存储过程。它仍然返回搜索结果并设置返回码。当我拉入第二个存储过程时,它按预期执行并创建存储过程,返回{storedProcedureName}_Result
并返回行。
有没有人看过这个问题,我该如何解决这个问题?我需要第一个存储过程来返回行,而不是返回代码。
跟进
我遇到了this question并让我的DBA看了一眼。但是对存储过程进行类似的更改仍然会使EF返回整数而不是复杂对象。 我还运行了所有字段为空的sproc并且除了返回代码之外还返回了空表结构。
这是存储过程:
USE [ourdatabase]
GO
/****** Object: StoredProcedure [dbo].[usp_Person_SearchPerson] Script Date: 01/30/2013 11:46:31 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_Person_SearchPerson]
@firstName nvarchar(50), --OR
@lastName nvarchar(50), --OR
@companyName nvarchar(150), --OR
@phoneNumber1 nvarchar(50), --OR
@phoneNumber2 nvarchar(50), --OR
@email nvarchar(100), --OR
@franchiseSetId uniqueidentifier, --AND
@recordSourceId uniqueidentifier --AND
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ReturnTable TABLE
(
PersonID UNIQUEIDENTIFIER,
FirstName NVARCHAR(50),
LastName NVARCHAR(50),
CompanyName NVARCHAR(150),
EmailAddress NVARCHAR(100),
PhoneNumber1 NVARCHAR(50),
PhoneNumber2 NVARCHAR(50),
Address1 NVARCHAR(50),
City NVARCHAR(100),
State NVARCHAR(50),
PostalCode NVARCHAR(20),
Score INT
)
-- flags to be used instead of calling the function udf_Strings_IsNullOrEmpty repeatedly
Declare
@firstNamebit bit, --OR
@lastNamebit bit, --OR
@companyNamebit bit, --OR
@phoneNumber1bit bit, --OR
@phoneNumber2bit bit, --OR
@emailbit bit, --OR
@franchiseSetIdbit bit, --AND
@recordSourceIdbit bit,
@rowID int
Insert into AppToolData..SearchLog
(
firstname ,
lastname ,
companyName ,
phoneNumber1 ,
phoneNumber2 ,
email ,
franchiseSetId ,
recordSourceID ,
StartTime_UTC
)
Values
(
@firstname ,
@lastname ,
@companyName ,
@phoneNumber1 ,
@phoneNumber2 ,
@email ,
@franchiseSetId ,
@recordSourceID ,
SYSDATETIMEOFFSET()
)
Select @rowID = SCOPE_IDENTITY()
-- working set to accumulate Person records meeting search criteria
--Declare #People table
Create Table #People
(
PersonID uniqueIdentifier
)
--work set of distinct person reocrds from previous working set
Declare @DistinctPeople table
(
PersonID uniqueIdentifier not null Primary Key
)
--Set flags
Select -- 0 = False (Is Not Null) 1 = True (Is Null)
@firstNamebit = dbo.udf_Strings_IsNullOrEmpty(@firstName),
@lastNamebit = dbo.udf_Strings_IsNullOrEmpty(@lastName),
@companyNamebit = dbo.udf_Strings_IsNullOrEmpty(@companyName),
@phoneNumber1bit = dbo.udf_Strings_IsNullOrEmpty(@phoneNumber1),
@phoneNumber2bit = dbo.udf_Strings_IsNullOrEmpty(@phoneNumber2),
@emailbit = dbo.udf_Strings_IsNullOrEmpty(@email)
DECLARE @MinimumWeight INT
SET @MinimumWeight = 1
DECLARE @AvailableWeight INT
SET @AvailableWeight = 0
If @franchiseSetId is not null
Begin
Select @firstName = '%'+@firstName+'%'
Select @lastName = '%'+@lastName+'%'
End
Else
Begin
Select @firstName = @firstName+'%'
Select @lastName = @lastName+'%'
End
If @franchiseSetId is null
Begin
-- first name provided, last name not provided, phone number not provided
IF @firstNamebit = 0 and @lastNamebit = 1 and @phoneNumber1bit = 1
BEGIN
SET @AvailableWeight = @AvailableWeight + 15 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where first name is a partial string match
Insert into #People
Select PersonID from Person p
Where (PatIndex(@firstName, p.FirstName)>0)
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
-- first name not provided, last name provided, phone number not provided
Else IF @firstNamebit = 1 and @lastNamebit = 0 and @phoneNumber1bit = 1
BEGIN
SET @AvailableWeight = @AvailableWeight + 20 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where last name is a partial string match
Insert into #People
Select PersonID from Person p
Where
(PatIndex(@lastName, p.lastName)>0)
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
-- first name provided, last name provided, phone number not provided
Else IF @firstNamebit = 0 and @lastNamebit = 0 and @phoneNumber1bit = 1
BEGIN
SET @AvailableWeight = @AvailableWeight + 30 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where first & last name are a partial string match
Insert into #People
Select PersonID from Person p
Where
(
(PatIndex(@firstName, p.FirstName)>0)
and
(PatIndex(@lastName, p.lastName)>0)
)
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
-- first name provided, last name not provided, phone number provided
IF @firstNamebit = 0 and @lastNamebit = 1 and @phoneNumber1bit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 45 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where first name is a partial string match
-- and Phone Number is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where
(PatIndex(@firstName, p.FirstName)>0)
and
pn1.Number = @PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
-- first name not provided, last name provided, phone number provided
Else IF @firstNamebit = 1 and @lastNamebit = 0 and @phoneNumber1bit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 50 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where last name is a partial string match
-- and Phone Number is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where
(PatIndex(@lastName, p.LastName)>0)
and
pn1.Number = @PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
-- first name provided, last name provided, phone number provided
Else IF @firstNamebit = 0 and @lastNamebit = 0 and @phoneNumber1bit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 65 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where first & last name are a partial string match
-- and Phone Number is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where
(
(PatIndex(@firstName, p.FirstName)>0)
and
(PatIndex(@lastName, p.LastName)>0)
)
and
pn1.Number = @PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
-- first name not provided, last name not provided, phone number provided
Else IF @firstNamebit = 1 and @lastNamebit = 1 and @phoneNumber1bit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 30 -- (First Name = 15, Last Name = 20, Phone Number = 30)
-- Add records where Phone Number is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where
pn1.Number = @PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
End
Else -- Indicates WORKCENTER/Drybook search
Begin
IF @firstNamebit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 15
-- Add records where first name is a partial string match
Insert into #People
Select PersonID from Person p
Where (PatIndex(@firstName, p.FirstName)>0)
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
IF @lastNamebit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 20
-- Add records where last name is a partial string match
Insert into #People
Select PersonID from Person p
Where
(PatIndex(@lastName, p.lastName)>0)
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
IF @phoneNumber1bit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 30
-- Add records where Phone Number 1 is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where pn1.Number = @PhoneNumber1
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
End
IF @phoneNumber2bit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 30
-- Add records where Phone Number 2 is an exact match
Insert into #People
SELECT
p.PersonId
FROM
Person p WITH (NOLOCK)
LEFT OUTER JOIN
PersonPhoneNumber ppn1 WITH (NOLOCK)
ON p.PersonId=ppn1.PersonId
LEFT OUTER JOIN
PhoneNumber pn1 WITH (NOLOCK)
ON ppn1.PhoneNumberId=pn1.PhoneNumberId
Where pn1.Number = @PhoneNumber2
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
IF @emailbit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 40
-- Add records where Email is an exact match
Insert into #People
Select
p.PersonId
from Person p
LEFT OUTER JOIN
PersonEmailAddress pea WITH (NOLOCK)
ON p.PersonId=pea.PersonId
LEFT OUTER JOIN
EmailAddress ea WITH (NOLOCK)
ON pea.EmailAddressId=ea.EmailAddressId
Where ea.[Address] = @email
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
IF @companyNamebit = 0
BEGIN
SET @AvailableWeight = @AvailableWeight + 10
-- Add records where Company Name is an exact match
Insert into #People
Select
p.PersonId
from Person p
LEFT OUTER JOIN
Company c WITH (NOLOCK)
ON p.CompanyId=c.CompanyId
Where c.Name = @companyName
AND
(
p.RecordSourceId = Coalesce(@recordSourceId, p.RecordSourceId)
--(@recordSourceId IS NULL)
--OR
--(p.RecordSourceId = @recordSourceId)
)
AND
(
p.FranchiseSetId = Coalesce(@franchiseSetId, p.FranchiseSetId)
--(@franchiseSetId IS NULL AND p.FranchiseSetId IS NULL)
--OR
--(p.FranchiseSetId = @franchiseSetId)
)
END
If @franchiseSetId is not null
Begin
-- WORKCENTER -- do not return results that are less than a 40% match of what was passed in
SET @MinimumWeight = @AvailableWeight * 0.4
End
Else
Begin
-- ClaimsEntry -- do not return results that are less than a 60% match of what was passed in
SET @MinimumWeight = @AvailableWeight * 0.6
End
-- get list of unique records
Insert into @DistinctPeople
Select Distinct PersonID from #People order by PersonID
INSERT INTO @ReturnTable (PersonID, FirstName, LastName, CompanyName, EmailAddress, PhoneNumber1, PhoneNumber2, Score)
(
SELECT
DistinctPeople.PersonId,
p.FirstName,
p.LastName,
c.Name,
ea.[Address],
null as PhoneNumber1,
null as PhoneNumber2,
Score =
(
--first name score
(
(CASE WHEN @firstNamebit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN PatIndex(@firstName, p.FirstName)>0 THEN 1 ELSE 0 END)
*
15
)
+
--last name score
(
(CASE WHEN @lastNamebit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN PatIndex(@lastName, p.LastName)>0 THEN 1 ELSE 0 END)
*
20
)
+
--email score
(
(CASE WHEN @emailbit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN ea.[Address] = @email THEN 1 ELSE 0 END)
*
40
)
+
--company score
(
(CASE WHEN @companyNamebit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN PatIndex(@companyName, c.Name)>0 THEN 1 ELSE 0 END)
*
10
)
)
FROM
@DistinctPeople DistinctPeople
LEFT OUTER JOIN
Person p WITH (NOLOCK)
ON DistinctPeople.PersonId=p.PersonId
LEFT OUTER JOIN
PersonEmailAddress pea WITH (NOLOCK)
ON p.PersonId=pea.PersonId
LEFT OUTER JOIN
EmailAddress ea WITH (NOLOCK)
ON pea.EmailAddressId=ea.EmailAddressId
LEFT OUTER JOIN Company c WITH (NOLOCK)
ON p.CompanyId=c.CompanyId
)
--If neither Phone number was passed as a parameter, the scores will not change
-- We can get rid of records that will not be returned
If @phoneNumber1bit = 1 and @phoneNumber2bit = 1
Begin
-- update the phone number scores, the actual phone number values
-- can be in either the first or second position
UPDATE rt
SET Score = Score +
(
(CASE WHEN @phoneNumber1bit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN rt.PhoneNumber1 = @phoneNumber1 THEN 1
WHEN rt.PhoneNumber2 = @phoneNumber1 THEN 1 ELSE 0 END)
*
30
)
+
--phone 2 score
(
(CASE WHEN @phoneNumber2bit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN rt.PhoneNumber1 = @phoneNumber2 THEN 1
WHEN rt.PhoneNumber2 = @phoneNumber2 THEN 1 ELSE 0 END)
*
30
)
FROM @ReturnTable rt
-- clear out the records we no longer care about
DELETE FROM @ReturnTable WHERE Score < @MinimumWeight
End
UPDATE rt
SET rt.PhoneNumber1 =
(
select top 1 xpn1.number
from PersonPhoneNumber xppn1 WITH (NOLOCK)
LEFT OUTER JOIN
PhoneNumber xpn1 WITH (NOLOCK)
on xppn1.PhoneNumberId =xpn1.PhoneNumberId
where xppn1.PersonId = rt.PersonID
order by (CASE
WHEN xpn1.Number = @phoneNumber1 then -999
else xppn1.SequenceNumber
end )
)
FROM @ReturnTable rt
UPDATE rt
SET rt.PhoneNumber2 =
(
select top 1 xpn1.number from PersonPhoneNumber xppn1 WITH (NOLOCK)
LEFT OUTER JOIN PhoneNumber xpn1 WITH (NOLOCK) on xppn1.PhoneNumberId =xpn1.PhoneNumberId
where xppn1.PersonId = rt.PersonID
and rt.PhoneNumber1 != xpn1.Number
order by (CASE
WHEN xpn1.Number = @phoneNumber2 then -998
else xppn1.SequenceNumber end )
)
FROM @ReturnTable rt
-- update the phone number scores, the actual phone number values can be in either the first or second position
UPDATE rt
SET Score = Score +
(
(CASE WHEN @phoneNumber1bit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN rt.PhoneNumber1 = @phoneNumber1 THEN 1
WHEN rt.PhoneNumber2 = @phoneNumber1 THEN 1 ELSE 0 END)
*
30
)
+
--phone 2 score
(
(CASE WHEN @phoneNumber2bit = 0 THEN 1 ELSE 0 END)
*
(CASE WHEN rt.PhoneNumber1 = @phoneNumber2 THEN 1
WHEN rt.PhoneNumber2 = @phoneNumber2 THEN 1 ELSE 0 END)
*
30
)
FROM @ReturnTable rt
-- clear out the records we no longer care about
DELETE FROM @ReturnTable WHERE Score < @MinimumWeight
UPDATE rt
SET Address1 = a.Address1,
City = a.City,
State = s.Abbreviation,
PostalCode = a.PostalCode
FROM @ReturnTable rt
OUTER APPLY
(
SELECT TOP 1 *
FROM PersonAddress pa WITH (NOLOCK)
WHERE pa.PersonId = rt.PersonID
ORDER BY pa.SequenceNumber
) ppa
LEFT JOIN Address a WITH (NOLOCK) on ppa.AddressId = a.AddressId
LEFT JOIN State s WITH (NOLOCK) on a.StateId = s.StateId
Update AppToolData..SearchLog
Set EndTime_UTC = SYSDATETIMEOFFSET()
Where rowid = @rowid
-- return only those that meet the minimum score/weight requirements
Delete FROM @ReturnTable WHERE Score < @MinimumWeight
SELECT * FROM @ReturnTable
--order by Score Desc
END
答案 0 :(得分:1)
根据cadrell0的信息和我们自己的测试,我们发现了以下内容:
生成表并从该表返回行的存储过程仅在运行时执行此操作。当实体框架使用fmtonly调用它时会抛出错误,因为没有创建运行时对象。
我们在存储过程中添加了FMTONLY OFF,允许Entity Framework查看表的格式,从而查看复杂对象的格式。
这允许我添加存储过程,获取正确的返回对象,现在我可以使用sproc在栅栏的数据库端执行搜索。
这对我们很重要,因为原始代码正在使用它和我们的代码HAD来使用它。