Mor*_*gan 2 c# sql linq entity-framework
从使用Entity Framework和linq的存储过程中请求数据时,会引发此异常。
An unhandled exception occurred while processing the request.
InvalidOperationException: Sequence contains more than one matching element
System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource> source,
Func<TSource, bool> predicate)
Run Code Online (Sandbox Code Playgroud)
堆栈的相关部分在这里(在两行上表示歉意,但是堆栈溢出编辑器不会让我在不离开代码块格式的情况下破坏它):
System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource> source,
Func<TSource, bool> predicate) Microsoft.EntityFrameworkCore.Query.Sql.Internal.FromSqlNonComposedQuerySqlGenerator.CreateValueBufferFactory(IRelationalValueBufferFactoryFactory relationalValueBufferFactoryFactory, DbDataReader dataReader) Microsoft.EntityFrameworkCore.Internal.NonCapturingLazyInitializer.EnsureInitialized<TParam, TValue>(ref TValue target, TParam param, Func<TParam, TValue> valueFactory) Microsoft.EntityFrameworkCore.Query.Internal.ShaperCommandContext.NotifyReaderCreated(DbDataReader dataReader) Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable+AsyncEnumerator+<BufferlessMoveNext>d__9.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Run Code Online (Sandbox Code Playgroud)
该错误是由于使用.FromSql作为linq查询的一部分进行数据库调用而引起的。我这样调用数据-即使它具有.ToListAsync(),堆栈跟踪也表明linq语句仍对返回的每个行项目调用.SingleOrDefault()-我假设这是有意的:
[HttpPost, Route("GetOneWeekRosters")]
public async Task<List<RosterLineView>> GetOneWeekRosters([FromBody] RosterSearch mysearch)
{
var dataentry = await _edb.RosterLineViews.FromSql("GetOneWeekRosters @Date, @DepartmentID, @RosterID, @RosterWeekID, @Active", new SqlParameter("@Date", mysearch.DateSelected), new SqlParameter("@DepartmentID", mysearch.DepartmentID), new SqlParameter("@RosterID", mysearch.RosterID), new SqlParameter("@RosterWeekID", mysearch.RosterWeekID), new SqlParameter("@Active", "true")).ToListAsync();
return dataentry;
}
Run Code Online (Sandbox Code Playgroud)
返回的数据集是此视图表示的直线平面数组:
public class RosterLineView
{
public int RosterLineID { get; set; }
public int RosterID { get; set; }
public int EmployeeID { get; set; }
public int RosterShiftID { get; set; }
public string RosterShiftName { get; set; }
public string Notes { get; set; }
public int RosterAreaID { get; set; }
public string RosterAreaName { get; set; }
public DateTime DateEntry { get; set; }
public int RosterWeekID { get; set; }
public DateTime RosterShiftStart { get; set; }
public DateTime RosterShiftFinish { get; set; }
public int ActivityTypeID { get; set; }
public string ActivityTypeShort { get; set; }
public decimal RosterHourValue { get; set; }
public int PositionID { get; set; }
public int DepartmentID { get; set; }
public int InstitutionID { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public decimal ContractedHours { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
该视图具有一个通过替代编码的组合键,如下所示:
modelBuilder.Entity<RosterLineView>()
.HasKey(c => new { c.RosterLineID, c.DateEntry, c.EmployeeID, c.PositionID });
Run Code Online (Sandbox Code Playgroud)
我已经使用调用中提供的样本数据检查了存储过程的结果,并可以使用这些键确认数据中是否存在重复项,如果有人认为问题出在那儿,我很乐意PM样本数据集,但是我尝试了一种独特的方法也要调用该程序。
关于为什么它仍然可能给出此错误的任何想法,这听起来好像有重复的数据返回了?虽然我假设这是给出异常的原因,但它可能与数据集无关,但与视图声明和复合键规范无关吗?我最初在删除的视图中确实有一个错误的[Key]批注,即使删除了它,是否也可能以某种方式对其进行了缓存?尝试调试4小时后,只是一些随机的想法。谢谢大家,感谢您的帮助。在接下来的几个小时内将离开PC,但是稍后我会再提任何意见。
编辑-这是所请求的存储过程
ALTER PROCEDURE [dbo].[GetOneWeekRosters]
-- Add the parameters for the stored procedure here
@Date varchar(20),
@DepartmentID int,
@RosterID int,
@RosterWeekID int,
@Active bit
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT distinct n.EmployeeID, n.FirstName, n.Surname, n.DepartmentID, n.InstitutionID,
n.ContractedHours, n.ReportingOrder, n.RoleName,
ISNULL(RosterLines.Notes, 'no notes') as Notes, ISNULL(RosterLines.ActivityTypeID, 8) as ActivityTypeID,
ISNULL(ActivityTypes.ActivityTypeShort, 'NW') as ActivityTypeShort,
ISNULL(RosterLines.RosterHourValue,0) as RosterHourValue,
ISNULL(RosterLines.RosterLineID, 0) as RosterLineID, ISNULL(RosterLines.PositionID, 1) as PositionID,
ISNULL(RosterLines.RosterShiftStart, m.DateDim) as ShiftStart,
RosterAreas.RosterAreaName, RosterShifts.RosterShiftName,
@RosterWeekID as RosterWeekID, @RosterID as RosterID,
ISNULL(RosterLines.RosterShiftFinish, m.DateDim) as ShiftFinish, ISNULL(RosterLines.RosterShiftID, 0) as RosterShiftID,
ISNULL(RosterLines.RosterLineID, 0) as RosterLineID, RosterLines.RosterAreaID,
m.DateDim as DateEntry from
(select DateDimension.DateDim, DateDimension.DayOfWeek_ShortName, DateDimension.Calendar_DayOfMonth
from DateDimension where DateDimension.DateDim between Convert(datetime,@Date,103) and (Convert(datetime,@Date,103) + 6)) m
cross join
(select Employees.EmployeeID, Employees.FirstName, Employees.Surname, Employees.EmploymentTypeID, Employees.ContractedHours,
Employees.RoleName, Employees.Active, EmploymentTypes.EmploymentTypeName, EmploymentTypes.ReportingOrder,
EmpToDepts.DepartmentID, EmpToDepts.InstitutionID
from Employees left join EmploymentTypes on Employees.EmploymentTypeID = EmploymentTypes.EmploymentTypeID
left join EmpToDepts on Employees.EmployeeID = EmpToDepts.EmployeeID
where EmpToDepts.DepartmentID = @DepartmentID and Employees.Active = @Active) n
left join RosterLines on n.EmployeeID = RosterLines.EmployeeID and n.DepartmentID = RosterLines.DepartmentID
and m.DateDim = RosterLines.DateEntry left join ActivityTypes on RosterLines.ActivityTypeID = ActivityTypes.ActivityTypeID
left join RosterAreas on RosterLines.RosterAreaID = RosterAreas.RosterAreaID
left join RosterShifts on RosterLines.RosterShiftID = RosterShifts.RosterShiftID
order by n.DepartmentID, n.ReportingOrder, n.Surname, n.FirstName
END
Run Code Online (Sandbox Code Playgroud)
小智 8
遇到相同的问题,我注意到我在多个列中使用了相同的列名。我检查了您的过程,似乎RosterLineID是重复的,这在某种程度上使EF感到困惑。遇到此错误时,请始终检查列名。希望这可以帮助...
小智 5
有同样的问题;正在运行EF Core 2.1并调用存储过程。对我来说,问题出在存储过程中。我有一个带有内部联接的SELECT *,它正在返回两个表的结果。我将存储过程更改为仅返回所需的表,从而解决了该问题。
这并不是一个很好的答案,但我通过使用 ADO.NET 获取存储过程来返回一个数据集。SPROC 确实有效,所以我相信真正的答案是 .net core 1.1 使用 linq 返回其数据集的方式的某种问题,也可能是它评估存储过程结果的方式。我没有时间证明这一点,但目前我有数据并且它很好。使用 SqlConnection、SqlDataReader 和 SqlCommand 手动生成该集只需要另外 50 行代码。我创建了一个列表,并在 While 循环中使用 SqlDataReader 迭代地将数据添加到其中。
这是痛苦的全部荣耀:
SqlConnection sqlconn = new SqlConnection("xxxxxxxxx");
sqlconn.Open();
SqlCommand sqlcomm = new SqlCommand("GetOneWeekRosters", sqlconn);
SqlParameter a = new SqlParameter("@Date", mysearch.DateSelected);
SqlParameter b = new SqlParameter("@DepartmentID", mysearch.DepartmentID);
SqlParameter c = new SqlParameter("@RosterID", mysearch.RosterID);
SqlParameter d = new SqlParameter("@RosterWeekID", mysearch.RosterWeekID);
SqlParameter e = new SqlParameter("@Active", true);
sqlcomm.Parameters.Add(a);
sqlcomm.Parameters.Add(b);
sqlcomm.Parameters.Add(c);
sqlcomm.Parameters.Add(d);
sqlcomm.Parameters.Add(e);
sqlcomm.CommandType = CommandType.StoredProcedure;
var rdr = await sqlcomm.ExecuteReaderAsync();
var mylist = new List<RosterLineView>();
while (rdr.Read()) {
int rosterid = int.Parse(rdr["RosterID"].ToString());
int rosterweekid = int.Parse(rdr["RosterWeekID"].ToString());
string firstname = rdr["FirstName"].ToString();
string surname = rdr["Surname"].ToString();
int employeeid = int.Parse(rdr["EmployeeID"].ToString());
int departmentid = int.Parse(rdr["DepartmentID"].ToString());
int institutionid = int.Parse(rdr["InstitutionID"].ToString());
decimal contractedhours = decimal.Parse(rdr["ContractedHours"].ToString());
int reportingorder = int.Parse(rdr["ReportingOrder"].ToString());
string notes = rdr["Notes"].ToString();
int activitytypeid = int.Parse(rdr["ActivityTypeID"].ToString());
string activitytypeshort = rdr["ActivityTypeShort"].ToString();
decimal rosterhourvalue = decimal.Parse(rdr["RosterHourValue"].ToString());
int rosterlineid = int.Parse(rdr["RosterLineID"].ToString());
int positionid = int.Parse(rdr["PositionID"].ToString());
DateTimeOffset shiftstart = DateTimeOffset.Parse(rdr["ShiftStart"].ToString());
string rosterareaname = rdr["RosterAreaName"].ToString();
string rostershiftname = rdr["RosterShiftName"].ToString();
DateTimeOffset shiftfinish = DateTimeOffset.Parse(rdr["ShiftFinish"].ToString());
int rostershiftid = int.Parse(rdr["RosterShiftID"].ToString());
int rosterareaid = int.Parse(rdr["RosterAreaID"].ToString());
DateTime datedim = DateTime.Parse(rdr["DateDim"].ToString());
var myitem = new RosterLineView();
myitem.RosterID = rosterid;
myitem.RosterLineID = rosterlineid;
myitem.RosterShiftFinish = shiftfinish;
myitem.RosterShiftStart = shiftstart;
myitem.ActivityTypeID = activitytypeid;
myitem.ActivityTypeShort = activitytypeshort;
myitem.ContractedHours = contractedhours;
myitem.DateDim = datedim;
myitem.DepartmentID = departmentid;
myitem.InstitutionID = institutionid;
myitem.Notes = notes;
myitem.PositionID = positionid;
myitem.RosterAreaID = rosterareaid;
myitem.RosterAreaName = rosterareaname;
myitem.RosterShiftID = rostershiftid;
myitem.RosterShiftName = rostershiftname;
myitem.Surname = surname;
myitem.FirstName = firstname;
myitem.RosterHourValue = rosterhourvalue;
myitem.RosterWeekID = rosterweekid;
mylist.Add(myitem);
}
sqlconn.Close();
rdr.Dispose();
return mylist;
}
Run Code Online (Sandbox Code Playgroud)
继续。