Мы храним элементы в нашей базе данных, которые получены из одного абстрактного объекта с именем SurveyItem.Мы пытаемся найти SurveyItems, которые содержат некоторую строку запроса.Я прошу прощения за стену кода, но я думаю, что это так мало, как я могу сделать это, оставаясь в нашей ситуации.Я подозреваю, что проблема вызвана наследованием объектов и использованием абстрактного корня.При использовании описанного ниже метода с сущностями без наследования все в порядке.
Наши сущности хранятся с использованием TpH и выглядят так:
public abstract class SurveyItem
{
[ScaffoldColumn(false)]
public int Id { get; set; }
[ScaffoldColumn(false)]
public virtual ICollection<Survey_SurveyItem> SurveyLinks { get; private set; }
[ScaffoldColumn(false)]
public abstract string Identifier { get; }
public SurveyItem()
{
SurveyLinks = new List<Survey_SurveyItem>();
}
}
public class SurveyHeaderItem : SurveyItem
{
[Required]
[Display(Name = "title", ResourceType = typeof(Caracal.Resources.GUI))]
public Translated Title { get; set; }
[ScaffoldColumn(false)]
public override string Identifier
{
get { return Title.NL + " / " + Title.EN; }
}
// ...
}
public class SurveyQuestion : SurveyItem
{
[Required]
[Order(1)]
[Display(Name = "question", ResourceType = typeof(Caracal.Resources.GUI))]
public Translated Question { get; set; }
[Order(2)]
[Display(Name = "description", ResourceType = typeof(Caracal.Resources.GUI))]
public TranslatedMultilineOptional Description { get; set; }
//...
}
Абстрактный корневой класс не содержит полей, которые мы хотимчтобы можно было проверить что-то вроде следующего невозможно:
Context.SurveyItems.Where(x => x.Field.contains(q));
Итак, мы попробовали следующую хранимую процедуру в сочетании с кодом ниже:
CREATE PROCEDURE SearchSurveyItems (@Q nvarchar(255))
AS
BEGIN
SET NOCOUNT ON;
SELECT i.*
FROM [dbo].SurveyItems AS i
WHERE
i.Question_NL LIKE ('%' + @Q + '%') OR
i.Question_EN LIKE ('%' + @Q + '%') OR
i.Description_NL LIKE ('%' + @Q + '%') OR
i.Description_EN LIKE ('%' + @Q + '%') OR
i.Title_NL LIKE ('%' + @Q + '%') OR
i.Title_EN LIKE ('%' + @Q + '%') OR
i.Text_NL LIKE ('%' + @Q + '%') OR
i.Text_EN LIKE ('%' + @Q + '%')
END
И вызовиз C #:
public IEnumerable<SurveyItem> SearchSurveyItems(string q)
{
return this.Database.SqlQuery<SurveyItem>("dbo.SearchSurveyItems @Q", new SqlParameter("Q", q)).ToList();
}
Это приводит к ошибке из заголовка:
System.ArgumentNullException was unhandled by user code
Message=Value cannot be null.
Parameter name: constructor
Source=System.Core
ParamName=constructor
StackTrace:
at System.Linq.Expressions.Expression.New(ConstructorInfo constructor, IEnumerable`1 arguments)
at System.Data.Common.Internal.Materialization.Translator.Emit_ConstructEntity(EntityType oSpaceType, IEnumerable`1 propertyBindings, Expression entityKeyReader, Expression entitySetReader, TranslatorArg arg, EntityProxyTypeInfo proxyTypeInfo)
at System.Data.Common.Internal.Materialization.Translator.Visit(EntityColumnMap columnMap, TranslatorArg arg)
at System.Data.Query.InternalTrees.EntityColumnMap.Accept[TResultType,TArgType](ColumnMapVisitorWithResults`2 visitor, TArgType arg)
at System.Data.Common.Internal.Materialization.Translator.ProcessCollectionColumnMap(CollectionColumnMap columnMap, TranslatorArg arg, ColumnMap discriminatorColumnMap, Object discriminatorValue)
at System.Data.Common.Internal.Materialization.Translator.Visit(SimpleCollectionColumnMap columnMap, TranslatorArg arg)
at System.Data.Query.InternalTrees.SimpleCollectionColumnMap.Accept[TResultType,TArgType](ColumnMapVisitorWithResults`2 visitor, TArgType arg)
at System.Data.Common.Internal.Materialization.Translator.TranslateColumnMap[TRequestedType](QueryCacheManager queryCacheManager, ColumnMap columnMap, MetadataWorkspace workspace, SpanIndex spanIndex, MergeOption mergeOption, Boolean valueLayer)
at System.Data.Objects.ObjectContext.InternalTranslate[TElement](DbDataReader reader, String entitySetName, MergeOption mergeOption, Boolean readerOwned)
at System.Data.Objects.ObjectContext.ExecuteStoreQueryInternal[TElement](String commandText, String entitySetName, MergeOption mergeOption, Object[] parameters)
at System.Data.Objects.ObjectContext.ExecuteStoreQuery[TElement](String commandText, Object[] parameters)
at System.Data.Entity.Internal.InternalContext.ExecuteSqlQuery[TElement](String sql, Object[] parameters)
at System.Data.Entity.Internal.InternalContext.ExecuteSqlQueryAsIEnumerable[TElement](String sql, Object[] parameters)
at System.Data.Entity.Internal.InternalContext.ExecuteSqlQuery(Type elementType, String sql, Object[] parameters)
at System.Data.Entity.Internal.InternalSqlNonSetQuery.GetEnumerator()
at System.Data.Entity.Internal.InternalSqlQuery`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Caracal.Entities.CaracalContext.SearchSurveyItems(String q) in J:\Caracal\Entities\CaracalContextDataAccessors.cs:line 48
at Caracal.Application.Controllers.SearchController.SurveyItem(String q) in J:\Caracal\application\Controllers\SearchController.cs:line 75
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
InnerException:
Обновление
Эта проблема исправлена при переименованиикласс SurveyItem для AbstractSurveyItem, и я создаю новый класс SurveyItem, унаследованный от AbstractSurveyItem.Затем он может идеально создавать объекты SurveyItem.
Однако я не считаю это реальным решением, поскольку теперь вы теряете безопасность и возможности абстрактного механизма.Есть ли способ, которым я могу сохранить класс абстрактным, но что EF все равно может его как-то сконструировать?Он имеет тип класса в каждой строке, поэтому, по крайней мере, теоретически у него должно быть достаточно информации для создания правильного экземпляра.
Обновление 2 *
ФактическиРешение из первого обновления удаляет исключение, однако оно также дает следующую проблему.А именно, каждый объект, который выходит, является только SurveyItem, а не подклассом, в результате чего получается бесполезный объект.