[英]Entity Framework 6 Code First function mapping
我想將 Entity Framework 6 集成到我們的系統中,但有問題。
問題是:
我無法通過 [Table]、[Column] 等屬性映射函數。 只有 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。 有人可以建議我如何將功能添加到模型中嗎? 添加函數的接口是暴露的,應該可以,但是web中沒有關於這種情況的信息。 可能有人知道 Entity Framework 團隊何時會為 Line To Sql 之類的函數實現屬性映射。
EF 版本:6.0.0-beta1-20521
謝謝!
是的,這對我有用。 但僅適用於標量函數。 我還需要 map 函數,它返回 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 中添加支持。 任何信息都會非常有用。
謝謝!
尚未嘗試過,但Entity Framework 6.1包含public mapping 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);
}
}
以下是所需的所有步驟 [已測試]:
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
您可以使用輔助方法從原始類型獲取 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
現在實體框架不是測試版,所以也許你解決了你的問題,但這個解決了我的問題如何在 linq to entity 中使用標量值函數?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.