20

Desidero integrare Entity Framework 6 nel nostro sistema, ma ho dei problemi.Entity Framework 6 Code Prima mappatura delle funzioni

  1. Desidero utilizzare il codice. Non voglio utilizzare il file Database First * .edmx per altri motivi.
  2. Uso la mappatura degli attributi [Tabella], [Colonna] e funziona perfettamente
  3. Il database ha molte funzioni definite dall'utente e ho bisogno di utilizzarle nella query Linq To Entities.

Il problema è:

Non posso mappare funzione tramite l'attributo come [Tabella], [Colonna]. È disponibile solo 1 attributo [DbFunction], che richiede il file * .edmx.

Sono ok ad avere il mapping delle funzioni nel file * .edmx, ma significa che non posso usare la mappatura degli attributi per le entità: [Tabella], [Colonna]. La mappatura deve essere piena in * .edmx o negli attributi.

Ho cercato di creare DbModel e aggiungere funzioni tramite questo codice:

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; 
    } 
} 

Ma avere eccezioni: sono stati rilevati

uno o più errori di convalida durante la generazione del modello:

Edm.String: : The namespace 'String' is a system namespace and cannot be used by other schemas. Choose another namespace name. 

Problema è nella variabile "edmType". Non riesco a creare correttamente ReturnType per la funzione. Qualcuno può suggerire come posso aggiungere la funzione nel modello? L'interfaccia di aggiunta funzione è esposta, quindi dovrebbe essere in grado di fare, ma non ci sono informazioni nel web per questa situazione. Probabilmente qualcuno sa quando il team di Entity Framework implementerà la mappatura degli attributi per funzioni come Line To Sql. Versione

EF: 6.0.0-beta1-20521

Grazie!


Sì, questo funziona per me. Ma solo per le funzioni scalari. Io, anche, bisogno di funzione, che restituisce IQueryable mappa:

IQueryable<T> MyFunction() 

Dove T è EntityType o ROWTYPE o qualsiasi tipo. Non riesco a farlo affatto (la versione EF è 6.0.2-21211). Penso che questo dovrebbe funzionare in questo modo:

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())); 
} 

ma ancora fortuna:

model.Compile(); // ERROR 

E 'possibile o no? Probabilmente i passi non sono giusti? Probabilmente il supporto verrà aggiunto a EF 6.1. Qualsiasi informazione sarà molto utile.

Grazie!

+0

Hai un DB e vuoi accedere tramite Codice? Non c'è bisogno quindi di un modello. Vedere http://msdn.microsoft.com/en-us/data/jj200620 –

risposta

3

È possibile ottenere il tipo di archivio dal tipo primitivo con un metodo di supporto:

public static EdmType GetStorePrimitiveType(DbModel model, PrimitiveTypeKind typeKind) 
    { 
     return model.ProviderManifest.GetStoreType(TypeUsage.CreateDefaultTypeUsage(
      PrimitiveType.GetEdmPrimitiveType(typeKind))).EdmType; 
    } 

Nel tuo esempio, che avrebbe dovuto cambiare il tipo di parametro di ritorno:

var edmType = GetStorePrimitiveType(model, PrimitiveTypeKind.String); 


Ho trovato l'aiuto di cui avevo bisogno qui: http://entityframework.codeplex.com/discussions/466706

+0

Come mappare la funzione componibile che risulta interrogabile di qualsiasi tipo? – Alexey

+0

Non sono sicuro di cosa stai chiedendo. Ho usato il codice di cui sopra per mappare una funzione scalare di DB in un metodo C# per confrontare un campo di concorrenza (byte []) e utilizzare quel metodo per comporre query. Forse la mia risposta originale sarà di aiuto: http://stackoverflow.com/a/20225824/2808810 – drew

1

ora Entity Framework non è beta, quindi forse risolvi d il tuo problema, ma questo risolto il mio problema How to use scalar-valued function with linq to entity?

+0

La domanda riguarda l'utilizzo della funzione con approccio code-first, hai collegato a una soluzione con il file .edmx, che non lo è. – Athari

+0

il fatto è che non v'è alcun modo per utilizzare una funzione scalare con Entity Framework utilizzando approccio in codice prima, ho cercato di farlo, e alla fine ha dovuto utilizzare quello che viene suggerito nel link – DanielV

+0

ho appena provato lo strumento per Entity Framework 6 e mi ha permesso di utilizzare l'approccio code-first – DanielV

12

non ho ancora provato questo, ma Entity Framework 6.1 includepublic mapping API. Moozzyk ha implementato Store Functions for EntityFramework CodeFirst utilizzando questa nuova funzionalità.

Ecco ciò che il codice è simile:

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

Posso restituire un tipo diverso da un tipo di tabella con questo? IE: Voglio restituire ObjectResult ? –

+1

@SarahBourt Non ne ho idea. Dovresti o porre una domanda su SO in modo appropriato o chiedere direttamente all'autore della biblioteca. – Athari

+3

Buona idea! Ho trovato la soluzione e l'ho postata come domanda/risposta qui: http: // StackOverflow.it/questions/29198416/using-ef6-store-functions-per-entityframework-codefirst-can-i-return-a-custom-t Spero che questo aiuti qualcun altro –

2

Ecco tutti i passi necessari [testati]:

Install-Package EntityFramework.CodeFirstStoreFunctions 

dichiarare una classe per il risultato di uscita:

public class MyCustomObject 
{ 
    [Key] 
    public int Id { get; set; } 
    public int Rank { get; set; } 
} 

Crea un metodo nella classe 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); 
} 

Aggiungere

public DbSet<MyCustomObject> SearchResults { get; set; } 

alla classe DbContext

Aggiungere nel sovrascritto OnModelCreating metodo:

modelBuilder.Conventions 
.Add(new CodeFirstStoreFunctions.FunctionsConvention<MyContextType>("dbo")); 

e ora si può chiamare/unirsi con a valori di tabella funzione come questa :

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