20

Я хочу интегрировать Entity Framework 6 в нашу систему, но проблема.Entity Framework 6 Code Первое сопоставление функций

  1. Я хочу использовать код First. Я не хочу использовать файл Database First * .edmx по другим причинам.
  2. Я использую сопоставление атрибутов [Таблица], [Столбец], и это отлично работает
  3. В базе данных есть много пользовательских функций, и мне нужно использовать их в запросе Linq To Entities.

Проблема:

Я не могу сопоставить функцию с помощью атрибута как [Таблица], [Колонка]. Доступен только 1 атрибут [DbFunction], для которого требуется * .edmx-файл.

У меня нормально иметь отображение функций в * .edmx файле, но это означает, что я не могу использовать сопоставление атрибутов для объектов: [Таблица], [Столбец]. Сопоставление должно быть заполнено в * .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() 

где Т 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. Любая информация будет очень полезна.

Спасибо!

+0

У вас есть БД и вы хотите получить доступ через код в первую очередь? Тогда нет необходимости в модели. См. Http://msdn.microsoft.com/en-us/data/jj200620 –

ответ

3

Вы можете получить тип магазина от примитивного типа с вспомогательным методом:

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

+0

Как сопоставить составную функцию, результат которой запрашивается для любого типа? – Alexey

+0

Я не уверен, что вы просите. Я использовал приведенный выше код для сопоставления скалярной функции DB с методом C# для сравнения поля параллелизма (byte []) и использовать этот метод для составления запросов. Может быть, мой оригинальный ответ поможет: http://stackoverflow.com/a/20225824/2808810 – drew

1

сейчас Entity Framework не является бета-версией, поэтому, возможно, вы решаете d ваша проблема, но это один решить мою проблему How to use scalar-valued function with linq to entity?

+0

Вопрос об использовании функции с использованием кода-первого подхода, вы связаны с решением с .edmx-файлом, а это не так. – Athari

+0

Дело в том, что нет возможности использовать скалярную функцию с каркасом сущности с использованием подхода, основанного на кодах, я пытался это сделать и, наконец, должен был использовать то, что предлагается в ссылке – DanielV

+0

Я просто попробовал инструмент для сущности framework 6 и разрешил мне использовать подход, основанный на кодах – DanielV

12

Не пробовал этого, но Entity Framework 6.1 включает public mapping API. Эта новая функциональность Moozzyk реализовала Store Functions for 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); 
    } 
} 
+0

Могу ли я вернуть другой тип, кроме типа таблицы, с этим? IE: Я хочу вернуть ObjectResult ? –

+1

@SarahBourt Я понятия не имею. Вы должны либо задать вопрос правильно, либо напрямую обратиться к автору библиотеки. – Athari

+3

Хорошая идея! Я нашел решение и разместил его как вопрос/ответ здесь: http: // stackoverflow.com/questions/29198416/using-ef6-store-functions-for-entityframework-codefirst-can-i-return-a-custom-t Надеюсь, это поможет кому-то другому –

2

Вот все шаги, необходимые [Испытано]:

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 класса

Добавить в перекрываться 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