Entity Framework 6 Code Первое отображение функции
Я хочу интегрировать Entity Framework 6 в нашу систему, но проблема.
- Я хочу использовать Code First. Я не хочу использовать файл Database First *.edmx по другим причинам.
- Я использую сопоставление атрибутов [Таблица], [Колонка], и это отлично работает
- В базе данных есть много пользовательских функций, и мне нужно использовать их в запросе Linq To Entities.
Проблема:
Я не могу сопоставить функцию с помощью атрибута, например [Таблица], [Столбец]. Доступен только 1 атрибут [DbFunction], для которого требуется *.edmx файл.
Мне нужно иметь отображение функций в файле *.edmx, но это означает, что я не могу использовать сопоставление атрибутов для Entities: [Table], [Column]. Сопоставление должно быть заполнено в *.edmx или в атрибутах.
Я попытался создать DbModel и добавить функцию через этот код:
public static class Functions
{
[DbFunction("CodeFirstNamespace", "TestEntity")]
public static string TestEntity()
{
throw new NotSupportedException();
}
}
public class MyContext : DbContext, IDataAccess
{
protected MyContext (string connectionString)
: base(connectionString, CreateModel())
{
}
private static DbCompiledModel CreateModel()
{
var dbModelBuilder = new DbModelBuilder(DbModelBuilderVersion.Latest);
dbModelBuilder.Entity<Warehouse>();
var dbModel = dbModelBuilder.Build(new DbProviderInfo("System.Data.SqlClient", "2008"));
var edmType = PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String);
var payload =
new EdmFunctionPayload
{
Schema = "dbo",
ParameterTypeSemantics = ParameterTypeSemantics.AllowImplicitConversion,
IsComposable = true,
IsNiladic = false,
IsBuiltIn = false,
IsAggregate = false,
IsFromProviderManifest = true,
StoreFunctionName = "TestEntity",
ReturnParameters =
new[]
{
FunctionParameter.Create("ReturnType", edmType, ParameterMode.ReturnValue)
}
};
var function = EdmFunction.Create("TestEntity", "CodeFirst", DataSpace.CSpace, payload, null);
dbModel.DatabaseMapping.Model.AddItem(function);
var compiledModel = dbModel.Compile(); // Error happens here
return compiledModel;
}
}
Но есть исключение:
Во время генерации модели были обнаружены одна или несколько ошибок проверки:
Edm.String: : The namespace 'String' is a system namespace and cannot be used by other schemas. Choose another namespace name.
Проблема находится в переменной edmType. Я не могу правильно создать ReturnType для функции.
Может ли кто-нибудь предложить, как я могу добавить функцию в модель?
Интерфейс функции добавления раскрывается, поэтому он должен быть в состоянии сделать, но в этой ситуации нет информации в Интернете.
Вероятно, кто-то знает, когда команда Entity Framework собирается реализовать сопоставление атрибутов для таких функций, как Line To Sql.
Версия EF: 6.0.0-beta1-20521
Спасибо!
Да, это работает для меня. Но только для скалярных функций. Мне также нужна функция отображения, которая возвращает IQueryable:
IQueryable<T> MyFunction()
Где T - тип EntityType или RowType или любой тип. Я не могу этого сделать вообще (версия EF 6.0.2-21211). Я думаю, что это должно работать следующим образом:
private static void RegisterEdmFunctions(DbModel model)
{
var storeModel = model.GetStoreModel();
var functionReturnValueType = storeModel.EntityTypes.Single(arg => arg.Name == "MyEntity").GetCollectionType();
var payload =
new EdmFunctionPayload
{
IsComposable = true,
Schema = "dbo",
StoreFunctionName = "MyFunctionName",
ReturnParameters =
new[]
{
FunctionParameter.Create("ReturnValue", functionReturnValueType, ParameterMode.ReturnValue)
},
Parameters =
new[]
{
FunctionParameter.Create("MyFunctionInputParameter", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32), ParameterMode.In)
}
};
storeModel.AddItem(EdmFunction.Create(
payload.StoreFunctionName,
"MyFunctionsNamespace",
DataSpace.SSpace,
payload,
payload.Parameters.Select(arg => MetadataProperty.Create(arg.Name, arg.TypeUsage, null)).ToArray()));
}
Но все равно не повезло:
model.Compile(); // ERROR
Возможно ли это или нет?
Возможно, шаги неправильные?
Вероятно, поддержка будет добавлена в EF 6.1.
Любая информация будет очень полезна.
Спасибо!
Ответы
Ответ 1
Еще не пробовал, но Entity Framework 6.1 включает API общедоступного сопоставления. Moozzyk внедрил Сохранить функции для EntityFramework CodeFirst, используя эту новую функциональность.
Вот что выглядит код:
public class MyContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new FunctionsConvention<MyContext>("dbo"));
}
[DbFunction("MyContext", "CustomersByZipCode")]
public IQueryable<Customer> CustomersByZipCode(string zipCode)
{
var zipCodeParameter = zipCode != null ?
new ObjectParameter("ZipCode", zipCode) :
new ObjectParameter("ZipCode", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext
.CreateQuery<Customer>(
string.Format("[{0}].{1}", GetType().Name,
"[CustomersByZipCode](@ZipCode)"), zipCodeParameter);
}
public ObjectResult<Customer> GetCustomersByName(string name)
{
var nameParameter = name != null ?
new ObjectParameter("Name", name) :
new ObjectParameter("Name", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.
ExecuteFunction("GetCustomersByName", nameParameter);
}
}
Ответ 2
Вы можете получить тип Store из примитивного типа с помощью вспомогательного метода:
public static EdmType GetStorePrimitiveType(DbModel model, PrimitiveTypeKind typeKind)
{
return model.ProviderManifest.GetStoreType(TypeUsage.CreateDefaultTypeUsage(
PrimitiveType.GetEdmPrimitiveType(typeKind))).EdmType;
}
В вашем примере вам придется изменить тип возвращаемого параметра:
var edmType = GetStorePrimitiveType(model, PrimitiveTypeKind.String);
Я нашел помощь, в которой я нуждался:
http://entityframework.codeplex.com/discussions/466706
Ответ 3
Вот все необходимые шаги [Tested]:
Install-Package EntityFramework.CodeFirstStoreFunctions
Объявить класс для результата вывода:
public class MyCustomObject
{
[Key]
public int Id { get; set; }
public int Rank { get; set; }
}
Создайте метод в классе DbContext
[DbFunction("MyContextType", "SearchSomething")]
public virtual IQueryable<MyCustomObject> SearchSomething(string keywords)
{
var keywordsParam = new ObjectParameter("keywords", typeof(string))
{
Value = keywords
};
return (this as IObjectContextAdapter).ObjectContext
.CreateQuery<MyCustomObject>(
"MyContextType.SearchSomething(@keywords)", keywordsParam);
}
Добавить
public DbSet<MyCustomObject> SearchResults { get; set; }
в класс DbContext
Добавьте в метод overriden OnModelCreating
:
modelBuilder.Conventions
.Add(new CodeFirstStoreFunctions.FunctionsConvention<MyContextType>("dbo"));
И теперь вы можете позвонить/присоединиться к
значения таблицы функционируют следующим образом:
CREATE FUNCTION SearchSomething
(
@keywords nvarchar(4000)
)
RETURNS TABLE
AS
RETURN
(SELECT KEY_TBL.RANK AS Rank, Id
FROM MyTable
LEFT JOIN freetexttable(MyTable , ([MyColumn1],[MyColumn2]), @keywords) AS KEY_TBL
ON MyTable.Id = KEY_TBL.[KEY]
WHERE KEY_TBL.RANK > 0
)
GO
Ответ 4
теперь Entity Framework не является бета-версией, поэтому, возможно, вы решили свою проблему, но эта проблема решила мою проблему Как использовать скалярнозначную функцию с linq для entity?