20

Tôi muốn tích hợp Khuôn khổ thực thể 6 vào hệ thống của chúng tôi, nhưng có vấn đề.Khuôn khổ thực thể 6 Mã Ánh xạ hàm đầu tiên

  1. Tôi muốn sử dụng Mã đầu tiên. Tôi không muốn sử dụng tệp Database First * .edmx vì các lý do khác.
  2. Tôi sử dụng ánh xạ thuộc tính [Bảng], [Cột] và công cụ này hoạt động tốt
  3. Cơ sở dữ liệu có nhiều hàm do người dùng xác định và tôi cần sử dụng chúng trong truy vấn LINQ to Entities.

Vấn đề là:

tôi không thể ánh xạ chức năng thông qua thuộc tính như [Bảng], [Column]. Chỉ có 1 thuộc tính có sẵn [DbFunction], yêu cầu tệp * .edmx.

Tôi muốn có chức năng ánh xạ trong tệp * .edmx, nhưng điều đó có nghĩa là tôi không thể sử dụng ánh xạ thuộc tính cho Đối tượng: [Bảng], [Cột]. Ánh xạ phải đầy trong * .edmx hoặc trong thuộc tính.

tôi đã cố gắng để tạo ra DbModel và thêm chức năng thông qua mã này:

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

Nhưng có ngoại lệ:

Một hoặc nhiều lỗi xác nhận đã được phát hiện trong thế hệ người mẫu:

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

Vấn đề nằm trong biến "edmType". Tôi không thể tạo chính xác ReturnType cho hàm. Ai có thể đề xuất cách tôi có thể thêm chức năng vào mô hình? Giao diện của chức năng thêm được hiển thị, vì vậy nó sẽ có thể làm, nhưng không có thông tin trên web cho tình huống này. Có lẽ, ai đó biết khi nào nhóm Entity Framework sẽ triển khai ánh xạ thuộc tính cho các hàm như Line To Sql.

Phiên bản EF: 6.0.0-beta1-20521

Cảm ơn!


Có, điều này phù hợp với tôi. Nhưng đối với chức năng vô hướng. Tôi cũng cần chức năng bản đồ, trả về IQueryable:

IQueryable<T> MyFunction() 

Trường hợp T là EntityType hoặc RowType hoặc bất kỳ loại nào. Tôi không thể làm điều này cả (phiên bản EF là 6.0.2-21211). Tôi nghĩ rằng điều này sẽ làm việc theo cách này:

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

Nhưng vẫn không có may mắn:

model.Compile(); // ERROR 

Có thể hay không? Có thể các bước không đúng? Có thể hỗ trợ sẽ được bổ sung tại EF 6.1. Mọi thông tin sẽ rất hữu ích.

Cảm ơn!

+0

Bạn có DB và muốn truy cập qua Mã trước? Không cần cho mô hình sau đó. Xem http://msdn.microsoft.com/en-us/data/jj200620 –

Trả lời

3

Bạn có thể nhận được các loại hàng từ các loại nguyên thủy với một phương pháp helper:

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

Trong ví dụ của bạn, bạn sẽ phải thay đổi loại tham số lợi nhuận của:

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


Tôi tìm thấy trợ giúp tôi cần ở đây: http://entityframework.codeplex.com/discussions/466706

+0

Làm thế nào để ánh xạ chức năng tổng hợp mà kết quả là có thể truy vấn được bất kỳ loại nào? – Alexey

+0

Tôi không chắc chắn những gì bạn đang yêu cầu. Tôi đã sử dụng mã trên để ánh xạ hàm DB vô hướng thành phương thức C# để so sánh trường đồng thời (byte []) và sử dụng phương thức đó để soạn truy vấn. Có lẽ câu trả lời ban đầu của tôi sẽ giúp: http://stackoverflow.com/a/20225824/2808810 – drew

1

bây giờ Entity Framework không phải là beta, vì vậy có thể bạn giải quyết d vấn đề của bạn, nhưng vấn đề này đã giải quyết được vấn đề của tôi How to use scalar-valued function with linq to entity?

+0

Câu hỏi đặt ra là sử dụng hàm với cách tiếp cận mã-đầu tiên, bạn đã liên kết với một giải pháp với tệp .edmx, mà không phải là. – Athari

+0

điều này là không có cách nào để sử dụng chức năng vô hướng với khung thực thể sử dụng cách tiếp cận mã đầu tiên, tôi đã cố gắng làm như vậy, và cuối cùng phải sử dụng những gì được đề xuất trong liên kết – DanielV

+0

Tôi vừa thử công cụ cho khung thực thể 6 và cho phép tôi sử dụng cách tiếp cận mã đầu tiên – DanielV

12

Chưa thử, nhưng Khuôn khổ thực thể 6.1 bao gồm public mapping API. Moozzyk đã triển khai Store Functions for EntityFramework CodeFirst bằng chức năng mới này.

Đây là những gì mã trông giống như:

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

Tôi có thể trả về một loại khác với loại bảng với điều này không? IE: Tôi muốn trả về ObjectResult ? –

+1

@SarahBourt Tôi không biết. Bạn nên đặt câu hỏi trên SO đúng cách hoặc hỏi trực tiếp tác giả của thư viện. – Athari

+3

Ý tưởng hay! Tôi tìm thấy giải pháp, và đăng nó như là một câu hỏi/câu trả lời ở đây: http: // stackoverflow.com/questions/29198416/using-ef6-store-functions-for-entityframework-codefirst-can-i-return-a-custom-t Hy vọng điều này sẽ giúp người khác –

2

Dưới đây là tất cả các bước cần thiết [Tested]:

Install-Package EntityFramework.CodeFirstStoreFunctions 

Khai báo một lớp cho kết quả đầu ra:

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

Tạo một phương thức trong lớp DbContext của bạn

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

Thêm

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

đến lớp DbContext bạn

Thêm vào overriden OnModelCreating phương pháp:

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

Và bây giờ bạn có thể gọi/join với một giá trị bảng hoạt động như thế này :

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 
Các vấn đề liên quan